Skip to content

III.5III · The agent loopdefense

Consent & containment - sandboxes, approvals, blast radius

You will not make an agent unhijackable, so the control that decides your outcome is the one that bounds what a hijacked agent can reach - containment sized before you ship, not consent collected after the fact.

Everything in Part III has pointed here. The model cannot separate instruction from data (II.2 · Prompt injection & the LLM attack surface), refusal training does not hold under narrative framing (III.3 · Browser & computer-use agents), and command-string guards do not survive contact with a shell (III.2 · Coding agents & Codex security). What remains is the boundary the agent runs inside and the gates it must pass to leave. Vendor documentation now says the quiet part out loud: “Sandbox isolation reduces the impact of a breach, but it does not eliminate risk” (Choose a sandbox environment, Anthropic, fetched 29 Jul 2026).

Why containment, and not the model layer

Anthropic published the cleanest available evidence on 25 May 2026. A red-team exercise phished an employee into running Claude Code with a prompt asking it to read ~/.aws/credentials, encode the contents, and POST them to an external endpoint. The result, in Anthropic’s own words: “Across 25 retries of that prompt, Claude completed the exfiltration 24 times” (How we contain Claude across products).

That is not a jailbreak statistic. The model-layer numbers in the same post are strong - Anthropic reports attack success held to “roughly 0.1% on single attempts, and around 5-6% after 100 adaptive attempts.” The exfiltration succeeded anyway, because when the user types the instruction there is nothing anomalous for a classifier to catch. The design principle Anthropic draws from it is the thesis of this chapter: “Design for containment at the environment layer first, then steer behavior at the model layer.”

The containment ladder

Each rung isolates a strictly larger scope at a strictly higher cost. Pick the rung by what you are willing to lose.

flowchart TB
  subgraph HOST["Host / cloud account"]
    subgraph VM["VM or microVM · own kernel"]
      subgraph CT["Container · namespaces, dropped caps, read-only root"]
        subgraph SB["OS sandbox · Seatbelt / bubblewrap"]
          A["Agent process<br/>+ every child process"]
        end
      end
    end
    PX["Egress proxy · allowlist,<br/>credential injection, audit log"]
  end
  A -->|"the only path out"| PX
  classDef d fill:#0f1a18,stroke:#5bd1c5,color:#bdeee2;
  classDef g fill:#1d1708,stroke:#e4a23f,color:#f0d8a8;
  class A d; class PX g;

The proxy is amber because it removes the exfiltration leg of the lethal trifecta. An agent with a perfect filesystem sandbox and open egress can still hand over everything it can read - which is exactly what the 24-of-25 result above demonstrates.

RungWhat it containsWhat it does not
Per-command OS sandbox (Seatbelt, bubblewrap)Bash commands and their child processes, at the OS levelThe agent’s own tools, MCP servers and hooks, which Anthropic says “are separate processes that run unconstrained on the host”
Whole-process sandbox runtimeThe entire agent process, so built-in tools and MCP servers are insideThe shared host kernel. Anthropic: “A kernel vulnerability could theoretically enable escape”
ContainerSeparate filesystem, process tree and network stackStill the host kernel, and whatever you mounted (see the credential table below)
gVisorSyscalls intercepted in userspace before reaching the host kernelCost. Anthropic documents file-I/O-heavy workloads at up to 10-200x slower
VM / microVMIts own kernel and virtualized hardware; Firecracker boots under 125 msNothing about the task. A VM holding production credentials is a contained breach of production
Remote / managedA vendor-run VM per session, git token held outside the sandboxYour data leaves your estate, and the vendor’s proxy becomes your egress policy

The rung is a separate decision from the permission mode. With prompts turned off, “the isolation boundary you choose is what protects your system,” and a per-command sandbox alone “is not sufficient for fully unattended runs.”

Two layers, or none

Filesystem and network isolation are not alternatives. Anthropic states that “effective sandboxing requires both filesystem and network isolation” (Claude Code sandboxing, 20 Oct 2025), and gives the reason in both directions: without network isolation a compromised agent exfiltrates SSH keys; without filesystem isolation it backdoors a shell startup file to get network access next run.

The shipping defaults, from the vendors’ own documentation:

AgentFilesystem defaultNetwork default
Claude Code sandboxed BashWrite: working directory plus session temp dir. Read: the entire computer, “except certain denied directories”No domains pre-allowed; prompts on first use. strictAllowlist denies instead
Codex CLIContext-dependent: version-controlled folders get Auto (workspace write, on-request approvals); non-version-controlled get read-only”By default, the agent runs with network access turned off”
Gemini CLIOff unless -s / --sandbox; it “is opt-in and must be explicitly enabled”. Default profile permissive-openpermissive-open allows network; -closed blocks; -proxied routes through a proxy

The four Codex approval policies are on-request, never, untrusted and granular.

This book’s judgment: egress allowlisting is the highest-leverage single control, and it is a judgment rather than a measured finding. It has two documented failure modes worth quoting to an architect. Breadth: “Allowing broad domains such as github.com can create paths for data exfiltration.” Depth: because the proxy decides from the client-supplied hostname without terminating TLS, “code running inside the sandbox can potentially use domain fronting or similar techniques to reach hosts outside the allowlist.” If your threat model needs more, you need a TLS-terminating proxy with its CA in the sandbox trust store, and you should assume some tooling ignores HTTP_PROXY entirely - which is why the strongest published pattern is --network none plus a Unix socket to a proxy outside the boundary. The same proxy is where credentials should live: the agent sends requests without them, the proxy injects them.

CVE-2026-54316 is the generalizable version of that first failure mode. In Claude Code, huggingface.co was pre-approved as a bare hostname for WebFetch, so every path on that domain skipped the permission prompt - including attacker-controlled model repositories. Injected content could trigger fetches to files the attacker writes, creating a covert channel for files, environment variables and command output. CWE-515, published 23 Jun 2026, fixed in 2.1.163. The rule: a domain-level allowlist is not an exfiltration control when the allowed domain hosts attacker-writable content with an observable side effect. Allowlist paths, or allowlist nothing.

Three escapes from 2026, and the rules they teach

EscapeMechanismThe rule
CVE-2026-25725 (7.7, 6 Feb 2026, fixed 2.1.2)The sandbox protected .claude/settings.local.json but not .claude/settings.json when absent at startup. Sandboxed code created it, injected a SessionStart hook, which ran with host privilegesThe sandbox’s own policy files are part of the sandbox. A gap that exists only for absent files is still a gap
CVE-2026-55607 (7.7, 25 Jun 2026, 2.1.38 to 2.1.163)Worktrees named .git, traversal outside the sandbox context, and git fsmonitor execution on an attacker path let a symlink chain overwrite ~/.zshenvConvenience carve-outs are attack surface. The worktree write allowance exists so git commit works; it became the escape
CVE-2026-50549 (CWE-59, Critical, Cursor < 3.0)The agent terminal sandbox fell back to the original path and wrote without approval when canonicalization failed; an in-workspace symlink forces that failureContainment must fail closed. A path check that gives up and proceeds is not a check

The fixes are as instructive as the bugs. Claude Code now “automatically denies write access to Claude Code’s settings.json files at every scope and to the managed settings directory,” and since v2.1.210 those deny rules resolve symlinks. Two review questions generalize past these products: which files does the agent read to decide its own policy, and are they inside its own deny set? And: when path resolution or the sandbox itself fails, does the action proceed?

Approval: where it works, where it is theater

ClaudeBleed is the cleanest case that consent can be forged rather than misled. It is a Claude for Chrome finding, disclosed by LayerX on 27 Apr 2026 and fixed in v1.0.70 on 6 May 2026, where a missing event.isTrusted check let a co-resident extension fire synthetic approvals; Manifold Security later reported the gap still reachable in v1.0.80. Different product from the two Claude Code CVEs above, same lesson: a dialog is only a control if only a human can satisfy it.

The MCP specification already carries the fix as a client SHOULD: “Show tool inputs to the user before calling the server, to avoid malicious or accidental data exfiltration.” Treat an approval gate as an authorization control only if it passes all four tests. Otherwise it is a blast-radius reducer, and you should call it that in writing when a risk committee asks.

  1. Resolved, not claimed. Does it display the canonicalized, post-resolution target - the real path, URL, or recipient - rather than the string the model supplied?
  2. Out of reach. Is the decision enforced somewhere the model cannot influence, including the parameters the boundary itself reads? (CVE-2026-50549.)
  3. Genuinely human. Can only a real user gesture satisfy it, with no flag, URL parameter, or IPC path that pre-satisfies it? (ClaudeBleed.)
  4. Still read. Is the prompt volume low enough that a human is actually reading? Anthropic’s stated reason for building the sandbox is “approval fatigue, where users might not pay close attention to what they’re approving,” and it reports the sandbox “safely reduces permission prompts by 84%.”

Test 4 is the one people resist, and it is why CoSAI’s Principles for Secure-by-Design Agentic Systems (16 Jul 2025) says “the goal is not to have humans approve every action,” calling instead for “strategic points of control that maximize oversight while minimizing intervention points,” plus “operational no-go zones for specific actions” and “risk-based thresholds that trigger human review.” A hundred prompts a day produce a hundred reflexive clicks.

Irreversible-action gating is where the remaining human attention goes. Reversibility, not sensitivity, is the sorting criterion: money moved, messages sent, data deleted, code merged or pushed, infrastructure destroyed, credentials rotated. Gate the class in the harness, not the phrasing in the prompt - Claude Code keeps content-scoped ask rules such as Bash(git push *) prompting even for sandboxed commands, which is the pattern to copy.

Budgets and rate limits are containment controls

  • Turn caps. max_turns raises MaxTurnsExceeded in the OpenAI Agents SDK; max_iterations does the same in Anthropic’s tool runners. Treat an agent that regularly hits the cap as a detection signal, not a tuning problem.
  • Token and spend ceilings per identity (IV.1 · Model APIs & the tool-use loop). Anthropic measured a multi-agent research system at roughly 15x the tokens of a chat interaction, so a budget sized for one agent strangles a swarm and a budget sized for a swarm bounds nothing for one agent.
  • Resource caps at the boundary. --memory 2g, --pids-limit 100 and a small tmpfs turn resource exhaustion into a failed command rather than a host outage.
  • Fail-closed on the high-blast-radius path (II.5 · Guardrails - what holds, and how to prove it), including the denial-of-service lever that fail-closed hands an attacker.

Sizing blast radius before you ship

Do this on paper, before the first deployment, and again whenever the tool set changes.

  1. Enumerate the tool set and mark each tool irreversible, outbound, privileged, or none. Two marks means a gate.
  2. Enumerate the identity, not the tools. What can the credential reachable from inside the boundary do, independent of which tool holds it? In this book’s experience this is where the answer stops matching the architecture diagram (IV.6 · Agent identity & access (NHI)).
  3. Enumerate reads, not just writes. Every file, secret and record inside the boundary, plus everything step 2’s credentials can pull in.
  4. Enumerate egress. Every reachable destination including allowlisted ones, and for each, whether it can relay data onward. Apply the CVE-2026-54316 test: can an attacker write content to it and observe the fetch?
  5. Write the incident report first. Assume total compromise on turn one with no model-level defense holding. If the report is unacceptable, you have the wrong rung or the wrong credentials inside it.
  6. Decide the revocation path (IV.6 · Agent identity & access (NHI), VII.3).