Three agents, one thing to steal
At Black Hat USA 2026, Novee broke the default setup of Claude Code, Gemini CLI, and Codex three different ways, each starting from a GitHub issue an anonymous stranger could file. The bypasses were unrelated — a quoting mismatch, an unenforced shell allowlist, a trusted AGENTS.md — but all three chains ended at the same step: read a real credential out of the agent's own process. Bromure Agentic Coding does not harden that last step. It empties the process, so the exfiltration runs and ships a decoy.
Three vendors, three unrelated harness bugs, one shared final move: read
the API key or token sitting in the agent's process and mail it out. In a
Bromure profile that value is a brm_… placeholder. The exfiltration
succeeds and the attacker receives a string that means nothing off your
Mac.
At Black Hat USA 2026 this week, Novee presented "Trusted Enough to Run: Breaking AI Agents in Official Workflows." Researcher Elad Meged tested the default configuration of three coding agents against each vendor's own public repositories, and broke all three. The write-ups landed on August 6.
The entry point was the same in every case, and it is the cheapest one there is: a GitHub issue or pull request opened by an anonymous stranger with zero privileges. The agent reads the untrusted text as part of its work, and the harness — the code around the model that decides what it may run — fails to keep that text on the far side of the line. Novee found the same vulnerable defaults on more than a hundred public repositories beyond the three vendors tested.
The three break paths have nothing to do with each other. They end in the same place, and that shared ending is the part worth taking home.
Three different doors, one back wall
Claude Code
The chain assigned CVE-2026-54316 used two seams. The first was a mismatch
between how Claude Code validated a command and how the shell actually
interpreted it: a quoted string that read as harmless to the validator parsed
differently once bash had it, and a git push --receive-pack flag rode
through twenty-three security checks
that were all, individually, doing their job. The second seam was
exfiltration. A read-only tac — the command that prints a file backwards —
was enough to read a secret and push it out reversed through GitHub Actions
logs, and a variant leaked the API key one character at a time by nudging a
public HuggingFace download counter and reading it back. Anthropic shipped
fixes.
Gemini CLI
Rated CVSS 10.0. In headless mode, Gemini CLI trusted the workspace folder
automatically and loaded whatever agent configuration it found there — no
sandbox, no approval — so a pull request that planted a config file ran
before the sandbox ever initialized. Two harness assumptions gave way: the
"restricted" shell allowlist was never enforced at runtime, and the
environment sanitization that scrubbed secrets from the child process left
them sitting in the parent process, readable through /proc. Google shipped
a breaking change to the headless trust model in 0.39.1 and
0.40.0-preview.3.
Codex
Codex runs two agent passes over a shared workspace. .git and .codex were
protected from writes; AGENTS.md was not, and it was reloaded as trusted
instructions on every run. The first pass, processing untrusted input, wrote
a poisoned AGENTS.md; the second, "safe" pass loaded it as authority and
carried the malicious instructions forward with elevated permissions. OpenAI
separated the passes into isolated jobs within three days.
The part that is the same
Novee's own summary is that "none of these were simple misconfigurations, they were correct security decisions that broke down at handoff points." That is the right read on the harness. But look at where each chain finishes.
Claude's tac reads a credential and the HuggingFace counter leaks the API
key. Gemini's /proc gap exposes the secrets in the parent process.
Codex's elevated second pass carries the environment's tokens into an
attacker-controlled instruction. Three unrelated seams open three different
ways, and each one ends by reaching for the same object: a real secret that
was sitting in the agent's process or environment, waiting to be read.
That is the assumption every one of these exploits shares — that if you get
code running as the agent, the credential is right there. It almost always
is. The ANTHROPIC_API_KEY, the GITHUB_TOKEN, the AWS keys: the ordinary
way to run a coding agent puts all of them in the process's environment,
because that is how the tools expect to find them.
Bromure Agentic Coding does not try to win the harness arms race. It removes what the harness is protecting.
Where the chain breaks
Bromure runs each profile's agent inside a disposable Linux VM on Apple Silicon, and routes every byte of its network traffic through a proxy on the host, outside the box the agent runs in. You can run the same autonomous issue-triage agent Novee attacked — you host it yourself instead of handing it a workflow runner. Walk the three chains against that layout and each one comes apart, and the credential step comes apart the same way for all three.
The credential is never in the process
This is the one that neutralizes the shared last step. The real Anthropic,
OpenAI, and xAI keys are injected into the VM as brm_… placeholders and
swapped for the real values only at the host proxy, on the wire, for the
one destination host each belongs to. The key is never in the VM's memory,
never in /proc, never in an environment variable a child or parent
process can read, never in a log. tac reads a decoy. The HuggingFace
counter leaks a decoy one character at a time. The /proc scrape returns
a decoy. Every exfiltration in the talk runs to completion and ships a
string that resolves on exactly one Mac, which is not the machine it ran
on.
The RCE lands in a box you can erase
"Code execution on the host running the agent" is the phrase in Gemini's advisory, and the host is the trust boundary Bromure moves. Gemini's pre-sandbox-init execution and Claude's shell bypass both get a throwaway Linux VM, one hypervisor from macOS, on NAT, where nothing on your network is reachable. Erase home discards whatever the run wrote and resets the home directory to its post-clone state. The exploit that owns the agent owns a VM you were going to throw away.
The write to main is refused at the proxy
Both the escalations aim at the same prize: Claude's chain pushes with
git push --receive-pack, Gemini's pushes malicious code into the main
branch. That is the supply-chain half — a compromised checkout becomes a
poisoned package downstream. Set the GitHub guardrail to read-only or
block-destructive and git-receive-pack is refused at the host proxy,
where a bypassed in-VM guard gets no vote. Fetches still pass; the push
that would poison the branch does not.
The instruction file is scored before it is obeyed
The entry is untrusted issue and PR text the harness failed to contain,
and Codex's whole chain lives in a written AGENTS.md. Bromure scores the
tool-result content the agent reads — web pages, issue bodies, file
contents — with a local prompt-injection model, and scores the authority
files themselves (CLAUDE.md, AGENTS.md, and their variants) with a
dedicated classifier plus a scanner for invisible-Unicode payloads. The
poisoned AGENTS.md between Codex's two passes is precisely what that
second detector is built to catch, and it runs on the host before the
model acts on the file.
Two of those settings are on by default, and the credential broker is not a setting at all — it is how a Bromure profile holds a secret in the first place. The covert channels round it out: the GitHub Actions log, the HuggingFace counter, the unexpected outbound host all cross the host proxy, and the Security Log and Trace Inspector record the host, status, and swap report for every request, so the side channel that leaked a decoy is also a row on a list you can read.
The harness will keep breaking
The three fixes Novee prompted are all good, and all narrow. Anthropic corrected the quoting mismatch; Google changed the headless trust model; OpenAI split the passes. Each closes the specific seam that was found. None of them changes the thing the three exploits had in common, which is that a working credential was sitting in the agent's process for the taking. The next harness bug — and Novee found the same defaults on a hundred other repositories, so there will be a next one — will reach for it again.
You can meet each disclosure with a patch and a config review, and you should. But the patch closes one door in one agent, and the review is per repository and per release. The credential a working exploit reaches for is the same across all three agents and every future bug, and it is the one thing you can move out of reach in a single decision: keep the real secret on the host, hand the agent a placeholder, and let the proxy produce the real value only for the host it is addressed to.
Install Bromure Agentic Coding, and give the agent a box — and a credential — you are willing to lose.