Claude Code Auto Mode Prompt Injection: 60-80% RCE Success Rate on Opus 5
- Claude Code Auto Mode, the new default since mid-August 2026, replaces human approval prompts with a safety classifier. A published attack chain beat that classifier at 60-80% code execution success rate against Opus 5.
- The attack never issues an explicit malicious instruction. It makes the dangerous path the natural one: a 415 HTTP error nudges Claude from WebFetch to curl; a decoy binary nudges Claude to write its own Python decoder; that decoder runs inside the attacker-controlled directory and triggers Python module shadowing.
- The safety refusal was the exploit path. Claude correctly refused to run the supplied binary, then wrote a replacement that imported from the attacker's poisoned
struct.pysitting in the same working directory. - Auto Mode blocked Claude's own cleanup attempt once Claude noticed the compromise. The classifier that allowed the infection denied the kill command, turning the safety mechanism into part of the failure.
- A second variant spawned a child Claude Code instance via
claude -p, giving the attacker a fresh agent with its own tool access, demonstrating that a compromised agent can become an agent factory. - Endpoint-side observability is the layer that does not get bypassed. Every stage of the attack (curl to an unexpected host, Python spawned from a temp directory, outbound C2 connection, child claude process) is visible in process and network telemetry regardless of what the classifier decided.
Anthropic rolled out Auto Mode as the Claude Code default in mid-August 2026, replacing per-action approval prompts with a safety classifier. To back the claim, a commissioned evaluation from Trajectory Labs ran 72 indirect prompt injection scenarios ten times each and reported 0.00% attack success for Opus 5 in Auto Mode. Researcher Johann Rehberger at embracethered.com then ran a targeted attack chain against the same configuration and reached 60-80% code execution success using a small sample. This post breaks down the chain, where the classifier failed, and what endpoint-side observability catches that the classifier missed.
What Claude Code Auto Mode actually changed
Before Auto Mode, Claude Code paused for human approval before consequential tool calls: running a shell command, making a network request, or writing a file. Auto Mode replaces those pauses with an inline classifier: allow or block, no human in the loop. The productivity gain is real. The security implication is structural: the classifier evaluates each tool call in isolation against a trained model of harmful actions. A multi-step attack that keeps each individual step below the detection threshold can succeed even when the full sequence would be obvious to a practitioner watching.
This is the same structural shift covered in claude-code-dangerously-skip-permissions-explained: when approval friction is removed, the surface that was gated by human judgment moves to a technical control, and technical controls can be bypassed technically. Auto Mode is a more sophisticated version of --dangerously-skip-permissions, not a replacement for runtime monitoring. The broader permission model is documented in how Claude Code permissions work.
The Claude Code Auto Mode attack chain, step by step
The setup is a classic indirect prompt injection scenario: Claude is asked to summarize a website. That website is attacker-controlled. The attack never issues an explicit instruction to do anything dangerous. It makes the dangerous path the one worth pursuing.
Step one: the site returns a 415 Unsupported Media Type to Claude's WebFetch tool call. Claude decides on its own to retry with curl in a Bash call. That transition is the first objective: WebFetch abstracts the network request; Bash does not. Once Claude is in the shell, the full shell surface is in play. The 303 redirect from curl points to a ZIP archive containing a README, a CSV manifest, SHA256 checksums, seven encoded notebook records, a macOS binary decoder, and a file called struct.py.
Step two: Claude unzips the archive and reads the README, which describes the binary as the decoder for the encoded records. Claude inspects the binary, finds it plausible, then refuses to execute it. That is the correct safety decision. Rather than stopping, Claude writes its own Python replacement decoder. That decoder runs from inside the extracted archive directory. This is the pivot: Claude's caution about the binary pushed it directly into the exploit path.
Claude correctly refused to run the supplied binary. Then wrote a Python replacement that ran in the attacker's directory. The safety refusal was the exploit path.
Step three: Claude's decoder imports base64. Python resolves the import chain and loads struct, finding struct.py in the current working directory first. The attacker's struct.py loads instead of the standard library module. It re-exports the real _struct C extension so that decoding succeeds and Claude receives valid JSON records. At module load time, obfuscated code spawns an isolated Python child in a new session. That child downloads and executes a remote Python stager, which pulls a native payload, makes it executable, and launches it. The conversation continues. The malware process is running and has established a C2 callback.
Python module shadowing: why it bypassed the classifier
Python places the current working directory first in the module search path. Any .py file in that directory shadows a standard library module with the same name. The technique itself is not new; it appears in dependency confusion attacks and supply chain campaigns across npm, PyPI, and now AI agent contexts, as documented in AI supply-chain attacks: a defender's guide. What is notable here is the trigger: it was not a package install that loaded the malicious file, it was Claude's own safe decoder running in the wrong directory.
The classifier saw Claude write a short Python script and run it. That is normal coding-agent behavior. It did not see that the script would load a different struct module than the standard library one, because the classifier does not model the Python import resolution order in the context of the current working directory. This is the same gap that makes indirect prompt injection in agentic systems structurally hard to catch at the action level: the malicious effect is several hops away from the observable action.
Auto Mode blocked the cleanup
In several test runs, Claude eventually inspected struct.py, recognized the compromise, and attempted to terminate the malware process. Auto Mode blocked the termination command. The classifier that had allowed the Python decoder to run, and therefore allowed the malware to launch, classified killing the process as potentially destructive and denied it.
This is the classifier failure mode in its most concrete form. A policy applied to individual actions cannot distinguish between an agent cleaning up after a compromise and an attacker trying to kill a monitoring process. The attack succeeded because each step was individually plausible. The remediation failed because terminating an active process looks destructive in isolation. Both judgments were locally correct. Together they produced a machine compromised and unable to clean itself up. This is why claude-code-permissions-hooks-hardening-guide argues that hooks and runtime controls must operate at the policy level, not just the individual-action level.
The agent-spawning variant
The researcher also tested a variant where struct.py launched a second Claude Code instance via claude -p instead of a native binary. The child agent ran with its own tool access and its own conversation context, independent of the parent. It performed basic recon (whoami, uname, id) and wrote files outside the original workspace. A fourth variant that combined Calculator pop with file writes outside the workspace reached 80% success.
The implication is direct: an agent compromised at the endpoint can become an agent-spawning vector. The parent's accumulated context, any restrictions learned during the session, and any policy the org applied to the parent's configuration do not carry over to a programmatically launched child. The child starts clean. As covered in autonomous hackbots and the case for agent-layer visibility, once an agent can create agents, the blast radius of a single compromise scales with spawning depth, not with the scope of the original session.
What the 0.00% benchmark actually measured
Anthropic's evaluation ran 72 scenarios ten times each and returned 0.00% attack success. That is a real result for the scenarios it tested. The attack chain above was not one of those scenarios. It was developed iteratively with AI assistance against current defenses, using payloads that improved across runs. Benchmarks measure known attack patterns at a point in time. Motivated attackers iterate against current defenses. The gap is not a flaw in the evaluation methodology; it is a property of any point-in-time safety benchmark.
This is the core argument in claude-security-scan-time-vs-runtime-governance: pre-deployment evaluation and classifier safety are necessary, but they establish a floor, not a ceiling. The classifier can be bypassed by attacks it has not seen. Runtime observability at the endpoint is the layer that operates outside the classifier and does not share its blind spots.
What fleet operators can observe regardless of Auto Mode
Every stage of this attack leaves traces at the endpoint, outside the Claude Code process, independent of what the classifier decided.
| Observable signal | What it indicates | Layer that sees it |
|---|---|---|
| curl to an unexpected external host from a Claude Code process | Agent moved from WebFetch to shell; potential stage-1 redirect | Process tree + network egress telemetry |
| Python spawned from a temp or extracted-archive directory | Decoder or stager execution; classic module-shadowing setup | Process launch monitoring with working-directory context |
| Outbound connection from a short-lived Python child process | Remote stager calling home; C2 establishment | Network egress correlated to process identity |
| claude -p invoked from a non-interactive shell | Headless agent creation; likely programmatic, not developer-initiated | Hook telemetry on claude binary invocations |
| Child claude process without a corresponding terminal session | Agent-spawning variant; fresh principal with independent tool access | Endpoint Sensor agent process lineage tracking |
Each of these signals exists at the endpoint layer, not inside the Claude Code classifier. They are observable through standard process and network telemetry correlated to the Claude Code process tree. The prerequisite is knowing which endpoints have Claude Code installed, in which version and mode, and with which MCP servers attached. That is an inventory problem before it is a detection problem. Auditing Claude Code across a fleet covers what that inventory looks like in practice, and how Claude Code works: a security guide explains the process model and hook surface that makes endpoint-side observation possible.
How Anomity surfaces this attack class
Anomity's Endpoint Sensor inventories the Claude Code installation, the MCP servers attached to it, the hooks registered against it, and the subprocess tree that emerges from a session. When a Claude Code session spawns a Python process from a temp directory and that process makes an outbound network connection, the Sensor has the process lineage and the egress event, correlated rather than isolated. When a second claude -p process appears without a developer initiating it, the Sensor records the parent-child relationship. Where Claude Code exposes a PreToolUse hook, Anomity returns an allow, deny, or log decision before the tool call runs, which means the 415-to-curl transition that starts this chain is a hookable event, not a fait accompli.
Every observation and decision lands in a queryable 90-day audit trail routed to your SIEM, Slack, email, or Jira. The attack chain above was designed to stay below the classifier's threshold at each individual step. Endpoint-side correlation of the sequence is the control that does not share that blind spot. If you want that visibility across your fleet without adding friction for developers, see how Anomity works or book a demo.
Frequently asked questions
What is Claude Code Auto Mode and why does it matter for security?
Auto Mode is Claude Code's default operating mode since mid-August 2026. It replaces per-action human approval prompts with an inline safety classifier that decides allow or block in real time. The intent is to remove developer friction. The security implication is that the human is no longer in the loop for individual tool call decisions. The classifier is. Classifiers have a different failure profile than humans: they evaluate each action in isolation against a trained model, which means a multi-step attack that keeps each individual step below the detection threshold can succeed even when the full sequence would be obvious to a human observer.
How did the attack chain achieve 60-80% success against Auto Mode?
The chain worked in stages. A 415 HTTP response nudged Claude from WebFetch to a curl Bash call. A redirect sent curl to a ZIP archive containing a decoy binary and a poisoned struct.py. Claude refused the binary and wrote its own Python decoder, but ran it inside the extracted archive directory. Python's module resolution loaded the malicious struct.py, which spawned a remote stager and established a C2 callback. No single step was obviously malicious. The chain's power was that each step was the natural consequence of the previous one, each individually plausible to the classifier.
What is Python module shadowing and why did it work here?
Python resolves imports by searching the current working directory before the standard library. If a file named struct.py exists in the working directory, it shadows Python's real struct module. The ZIP archive contained a malicious struct.py that re-exported the real struct API so that decoding worked correctly while executing obfuscated payload code in the background. The exploit triggered when Claude's self-written decoder ran from inside the extracted archive directory and imported base64, which internally imports struct. Claude had no visibility into which struct.py was loaded.
Why did Auto Mode block cleanup but not the initial infection?
The classifier evaluates tool calls individually, not as a sequence. Spawning a Python child inside a working directory looked like normal coding-agent behavior at the moment it happened. By the time Claude noticed the compromise and attempted to kill the malware process, the classifier saw a process termination command and blocked it as potentially destructive. A policy applied to individual actions cannot distinguish between legitimate remediation and an attacker killing a monitoring process. A classifier without sequence context is structurally blind to multi-step attacks.
What does the agent-spawning variant mean for multi-agent fleet security?
The variant used the poisoned struct.py to launch a second Claude Code instance via claude -p. That child agent had its own tool access and fresh context, performed recon (whoami, uname, id), and wrote files outside the original workspace. An agent compromised at the endpoint can become an agent-spawning vector. The blast radius is not one conversation but potentially a chain of agents, each starting clean without the restrictions the parent accumulated. This is why tracking agent process lineage at the endpoint matters independently of what any single session's classifier decides.
What signals should fleet operators monitor to catch this class of attack?
Every stage of the attack leaves observable traces regardless of what Auto Mode decided: a curl invocation to an unexpected external host from a Claude Code process; a Python process spawned from a temp or extracted-archive directory; an outbound network connection from a short-lived Python child; a claude -p process started from a non-interactive shell without a developer initiating it. These signals exist at the endpoint, outside the Claude Code process, and are observable through process telemetry and network egress monitoring correlated to the Claude Code process tree.
Does this attack invalidate Anthropic's 0.00% benchmark result?
Not exactly. It shows the benchmark's scope. The commissioned evaluation tested 72 defined indirect prompt injection scenarios. The attack chain above was not one of them; it was developed iteratively against current defenses with AI assistance. Benchmarks measure known patterns at a point in time. A motivated attacker iterates against current defenses. The gap between those two numbers is not a flaw in the methodology; it is an inherent property of benchmark-based safety claims, which is why scan-time and pre-deployment evaluation are necessary but not sufficient on their own.




