← Contents Volume X · Lecture 22

Volume X · Managing Context and Trust

22

What an Agent Is Allowed to Touch

An agent that can read a file, run a command, or send a request is an agent that can do those things to the wrong file, the wrong command, or the wrong destination. This lecture is about three separate answers to that risk, each aimed at a different point of failure — and about being honest that stacking all three still does not close the loop completely.

The mental model

Permission modes decide whether an action runs at all. Sandboxing decides what that action can reach even once it runs. The "lethal trifecta" explains why neither one fully closes the loop once an agent reads untrusted content while holding both data access and an outbound channel. No single layer is enough; that is the design, stated plainly rather than hidden.

Six modes, one spectrum

Claude Code's permission-modes documentation (code.claude.com/docs/en/permission-modes) lays out six modes along a single axis from oversight to convenience. default ("Manual") permits reads only, prompting for anything else. plan is also reads only — Claude researches and proposes a plan but cannot edit source until that plan is approved, the mode this whole site's own house rules describe as "no code until approved." acceptEdits extends default with file edits and common, working- directory-scoped filesystem commands — mkdir, touch, rm, mv, cp, sed — auto-approved without a prompt each time. auto allows everything, but gated by a background classifier model that blocks actions escalating beyond what was actually asked for, actions targeting infrastructure it does not recognize, or actions driven by hostile content Claude read rather than by the user's own instruction. dontAsk auto-runs only pre-approved tools and read-only commands; everything else is auto-denied, not prompted — built for CI and other locked-down environments where no human is present to answer a prompt. bypassPermissions allows everything, including writes to otherwise-protected paths, and is documented as appropriate only "for isolated containers and VMs."

Two details are worth holding onto past the taxonomy itself. First, even bypassPermissions still hard-prompts on rm -rf / or rm -rf ~ — a circuit breaker that survives every other permission being waived. Second, the documentation states its own limit without hedging: "bypassPermissions offers no protection against prompt injection or unintended actions." Turning off prompts does not turn off risk; it only removes the checkpoint that would have caught it.

The six permission modes, ordered from most to least oversight
ModeWhat runs unpromptedRisk posture
planNothing — reads only, proposes a plan, no edits until approvedLowest
default (Manual)Reads onlyLow
acceptEditsReads, file edits, common scoped filesystem commandsModerate
dontAskOnly pre-approved tools + read-only commands; else auto-deniedModerate, unattended-safe
autoEverything, gated by a background classifierElevated, classifier-bounded
bypassPermissionsEverything, including protected-path writesHighest — containers/VMs only

auto mode's classifier works from an explicit taxonomy, not a vague sense of caution. Blocked by default: piping a remote script into a shell (curl | bash), sending sensitive data externally, production deploys or migrations, force pushes, granting IAM or repository permissions, merging an unapproved pull request, or printing live credentials into the visible transcript. Allowed by default: local file operations inside the working directory, installing declared dependencies, and read-only HTTP requests. And the classifier's own inputs are deliberately narrowed — it sees user messages, tool calls, and CLAUDE.md content, but tool results are stripped out before they reach it. That stripping is a direct, named defense against prompt injection: hostile text embedded in a file or a webpage the agent reads cannot manipulate the classifier directly, because the classifier never sees that text in the first place.

A second, independent layer: the sandbox

Permission modes answer whether a tool call runs. Claude Code's sandboxing documentation (code.claude.com/docs/en/sandboxing) answers a different question: even once a Bash call is allowed to run, what can it actually reach at the operating-system level. Two independent isolation layers do this. Filesystem isolation uses Seatbelt on macOS and bubblewrap plus socat on Linux/WSL2. Network isolation routes traffic through an external proxy enforcing a domain allowlist — no domain is pre-allowed by default.

The default filesystem policy restricts write access to the working directory plus a session temp directory, but read access is broad — effectively the whole machine — except for paths explicitly denied. That default gap is documented plainly and is worth stating without softening: unless an operator adds sandbox.credentials deny rules, the default read policy still permits reading ~/.aws/credentials and ~/.ssh/. The network proxy enforces on the requested hostname, but it does not terminate or inspect TLS by default — it cannot see what is inside an allowed connection's payload, which the documentation flags directly as an exfiltration risk via domain fronting on broadly-allowed domains such as github.com. The documentation is explicit that sandboxing and permission modes are not substitutes for each other: sandboxing is about what a process can touch at the OS level; permission modes are about whether the tool call runs at all. They compose; neither replaces the other.

The lethal trifecta

Simon Willison's "lethal trifecta" post (simonwillison.net/2025/Jun/16/the-lethal-trifecta/) is informed practitioner commentary, not a peer-reviewed source, and is flagged as such here deliberately. Its claim is that three capabilities, present together in one agent, make it exploitable through prompt injection: access to private data, exposure to untrusted content, and the ability to communicate externally — an exfiltration channel. Any two of the three are survivable; the argument is that all three together is "lethal," because nothing forces an attacker's instructions, smuggled inside a document or email or webpage the agent reads, to look any different from the user's own. Willison states the mechanism directly: "LLMs are unable to reliably distinguish the importance of instructions based on where they came from" — there is no reliable in-band signal that separates a trusted instruction from a hostile one embedded in content the agent was only supposed to read.

The post is not abstract — it cites concrete, disclosed production exploits as evidence that the pattern is real rather than theoretical: Microsoft 365 Copilot in June 2025, GitHub's own official MCP server in May 2025, and the GitLab Duo Chatbot in May 2023. Each involved an agent with the same three ingredients present at once.

THE LETHAL TRIFECTA PRIVATE DATA ACCESS UNTRUSTED CONTENT EXPOSURE EXTERNAL COMMUNICATION CHANNEL DANGER ZONE all three at once = exfiltration path
Figure 22a Any two circles alone are survivable. The triple overlap — data worth stealing, a way for an attacker's instructions to reach the agent, and a channel for the result to leave — is where injected instructions become a real exfiltration path.

What each layer actually stops, and what it doesn't

Permission modes stop an unapproved action from running at all — but a classifier that never sees tool results cannot catch everything, and bypassPermissions states plainly that it stops nothing related to injection. Sandboxing stops a running action from reaching most of the filesystem or network — but the documented default gap (credentials still readable, TLS not inspected) means "most" is not "all." The lethal trifecta names the precondition that makes the remaining gap dangerous: an agent that combines private data, untrusted content, and an outbound channel is exploitable no matter how good any single layer is, because the failure is in the model's inability to separate trusted instructions from injected ones, not in any one control surface.

Read the primary source