Volume X · Managing Context and Trust
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.
| Mode | What runs unprompted | Risk posture |
|---|---|---|
| plan | Nothing — reads only, proposes a plan, no edits until approved | Lowest |
| default (Manual) | Reads only | Low |
| acceptEdits | Reads, file edits, common scoped filesystem commands | Moderate |
| dontAsk | Only pre-approved tools + read-only commands; else auto-denied | Moderate, unattended-safe |
| auto | Everything, gated by a background classifier | Elevated, classifier-bounded |
| bypassPermissions | Everything, including protected-path writes | Highest — 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.
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
- Permission Modes — Claude Code documentation.
- Sandboxing — Claude Code documentation.
- The Lethal Trifecta for AI Agents — Simon Willison.