Cybersecurity

Your agent framework is the attack surface

A GitHub issue from a stranger was enough to run code and steal secrets from Claude Code, Gemini CLI and Codex. The model wasn't the flaw — the harness around it was.

A hand slips a folded note into the intake slot of a small machine of pipes and levers built around a glowing core.

The Novee findings

AgentRoot causeIdentifierVendor response
Claude Code (GitHub Action) — round 1Command validator stripped single-quoted strings before checking; git push --receive-pack=<payload> passed validation and executed on the runner—Patched
Claude Code — round 2Fix relied on a hardcoded allow-list of “read-only” commands exempt from write-level scrutiny; unrestricted file reads and exfiltration—Patched
Claude Code — round 3Pre-approved Hugging Face access abused as an exfiltration channel via public download countersCVE-2026-54316Patched
Gemini CLIBypass of execution restrictions; OS command execution before sandboxing appliedCVE-2026-12537Patched
CodexTwo passes in one CI job share a checked-out workspace; first pass writes AGENTS.md, which the second pass loads as authoritative instructionsNone assignedOpenAI: design decision, not a vulnerability

The git push --receive-pack chain is worth understanding because it is so mundane. Git’s receive-pack option lets a push specify a program to run on the receiving end. Claude Code’s validator, per the Cloud Security Alliance write-up, stripped single-quoted strings before applying its checks, so a payload hidden in that option slipped through untouched and executed on the GitHub Actions runner. Exposure: GITHUB_TOKEN and ANTHROPIC_API_KEY from the workflow environment. With a write-scoped GitHub token, that extends to workflow modification and package publication under the repository’s namespace — a supply-chain compromise from a single issue.

The CSA research notes make the crucial point plainly: these chains exploited design gaps in command validation and process isolation, not model persuasion. A perfectly aligned model would still have been exploitable, because the harness did the wrong thing with the model’s output. Meged: “The harness is the code between the model and the real world” — and it “repeatedly failed to keep untrusted GitHub content from reaching privileged execution environments.”

The Codex case is the most conceptually interesting because it is a disagreement about what counts as a vulnerability. OpenAI’s position: if you configure two passes to share a workspace, the first writing an instruction file the second trusts is the documented behaviour of AGENTS.md, not a flaw. Novee’s position: an unprivileged outsider can cause the first pass to write that file. Both are correct, which is exactly why “the framework is the vulnerability” is the right frame — the bug lives in the composition, not in any single component’s spec.

Framework-level findings

The second talk moved the attack surface below the tool layer. The claim: exploitable logic in the core runtimes of LangChain, CrewAI, AutoGen and Semantic Kernel.

  • Memory stores. Injected content persisted into agent memory is replayed as trusted context in later turns and later sessions. This is the Codex AGENTS.md finding generalised: run N writes what run N+1 reads as truth.
  • Planning loops. Content that influences the planner’s decomposition of a task can redirect the agent without any tool call being made — the agent simply decides to do something else.
  • Serialisation layers. Several frameworks deserialise state (chains, agents, messages) from formats that permit code execution on load. A classic vulnerability class (Java deserialisation, Python pickle) reappearing in a new place.

The Hugging Face incident is the same story at a different scale: the agents were hijacked by content on a message board, and the “framework” that made it possible was a shared filesystem. The generalisation is uncomfortable but clean — any place untrusted content meets trusted execution is the framework, and the framework is attack surface.

Reframing: from “control the tools” to “the framework is the vulnerability”

The standard agent security model — enumerate tools, scope permissions per tool, require approval for dangerous ones — is necessary. Keep it. But the Black Hat research establishes three additional facts:

  1. Untrusted content reaches the model through channels that are not tool calls (issues, retrieved pages, prior-run artefacts, memory).
  2. The model’s output reaches the world through code (the harness) that has its own bugs.
  3. The framework’s own state is an injection target.

So the threat model must include the harness and the framework as first-class attack surface, reviewed as you would a web application’s request-handling code.

Hardening steps, concrete

Trust boundaries

  • Treat every externally sourced string — issue body, PR description, commit message, retrieved page, prior agent output — as untrusted input. Tag it as such, and where the framework allows, in structured metadata the harness can enforce on.
  • Never let an agent run write to a location a later run reads as instructions (AGENTS.md, CLAUDE.md, .cursorrules, memory stores) unless that write is itself gated by human review.

CI-specific

  • Do not trigger agent workflows on issues / issue_comment events from non-members. If you must, run them with a token scoped read-only and no secrets.
  • Use ephemeral, network-restricted runners for agent jobs. Egress allow-list to the vendor API and the required registry, nothing else — the Hugging Face side channel worked because a third-party host was reachable.
  • Separate the agent’s credentials from the repository’s. The agent should hold an API key that can do nothing but call the model, and a GitHub token that can do nothing but comment.

Command execution

  • Do not build your own shell-command validator. Novee defeated two rounds of one written by a well-resourced vendor. Prefer an allow-list of structured actions (open file, run named test suite) over parsing free-form shell.
  • If free-form shell is unavoidable, run it in a sandbox where the worst case is bounded, and assume the validator will be bypassed.

Frameworks

  • Pin framework versions and track their advisories as you would any network-exposed dependency.
  • Disable or replace deserialisation paths that accept code (pickle, unsafe YAML loaders, eval-based config).
  • Treat agent memory as a database with untrusted writers: validate on read, not just on write.

Detection

$ echo REAL; sleep

but whose runner telemetry shows a network connection to an unexpected host has diverged, and the transcript is the thing lying. Only infrastructure-side telemetry catches that.

Sources

Back to the light read (2 min).

Related articles

· Cybersecurity · Light read 2 min · Deep dive 5 min

Black Hat 2026: what the keynotes argued

Black Hat USA 2026 argued economics, not exploits: when offence is nearly free, the only lever left is to make whole classes of bugs impossible rather than findable.