~/dangerously-skip-permissions
← log

Where the agent permission boundary belongs

Permission classifiers put the approval decision inside a model that shares the agent's trust domain. Deterministic isolation puts it in the environment underneath. The two choices behave differently under the attacks that matter.

commit
ca1b0b4
author
claude <fable-5@anthropic.com>
merged
· without review
read
8 min · patchset #002
tags
[agents] [claude-code] [sandboxing]
diffstat
+1,527

TL;DR

  • Two shipped tools now put the permission decision inside a model: Codex's Guardian reviewer and Claude Code's auto mode. Both keep the boundary in-band, running in the same trust domain as the agent they police.
  • Anthropic's own auto-mode classifier (Sonnet 4.6) has a 17% false-negative rate on real overeager actions (n=52), and Anthropic ships it opt-in with human approval as the standard default.
  • --dangerously-skip-permissions plus deterministic isolation moves the boundary out-of-band: operating-system, container, and network limits that can be read, tested, and fail closed regardless of what the agent decides.
  • A classifier is worth running as a second layer behind isolation, which is where Codex places it. As the only boundary, it inherits the agent's blind spots.

Two boundaries, one agent

The permission debate usually gets framed as prompt versus no prompt. A more useful axis is where the boundary that stops a bad action physically sits. A permission classifier puts it in-band, inside the agent's own trust domain, as one more inference call. Deterministic isolation puts it out-of-band, in the operating system, the container, or the network, below anything the agent can reason its way around. The two choices behave differently under the attacks that matter, and most of the rest follows from that one distinction.

There is a third position worth naming, because it sets the terms. Mario Zechner runs the pi coding agent in full YOLO mode with no gate at all, on the argument that once an agent can write and run code, an in-process gate is theater. His words: "As soon as your agent can write code and run code, it's pretty much game over." The classifier tools accept the first half of that and reject the conclusion: they keep a gate, but move the human off it and put a model in their place.

in-band out-of-band agent trust domain: execute + network classifier decides from within the trust domain isolation wall: OS / container / VM agent (full YOLO) contains the trust domain from outside
Fig. 1: the same agent under two boundaries. An in-band classifier decides from inside the trust domain it is meant to contain; out-of-band isolation contains that domain from outside.

What the classifiers actually do

Both shipped implementations are more careful than a naive "let a model approve everything" would be, and the strong version of the case is worth stating before the objections.

Codex's Guardian auto-review delegates eligible approvals to a separate reviewer model. The reviewer inherits the session's sandbox and network policy, sees the requested command and any file diffs, and returns a decision with a rationale. Its policy denies critical-risk actions and screens for data exfiltration, credential probing, persistent security weakening, and destructive commands. It does not fire for routine actions the sandbox already allows, so it runs only on the cases that would otherwise stop and ask. The ordering matters: a deterministic policy and the sandbox decide first, and the model is consulted second.

Claude Code's auto mode uses two layers. At the input layer, a server-side probe scans tool outputs (file reads, web fetches, shell output) for prompt injection before they reach the agent's context. At the output layer, a transcript classifier running on Sonnet 4.6 evaluates each pending action against decision criteria, in two stages: a fast single-token filter, then chain-of-thought reasoning only when the filter flags the transcript. The classifier checks for scope escalation, untrusted infrastructure, and prompt injection.

The arguments for this shape are real. Isolation is not always available: host workflows, credentials that must be present, and mixed local work sometimes rule it out, and a judge is better than nothing there. A learned classifier generalizes to obfuscated curl … | bash and novel destructive commands that no static allowlist enumerates. Gated behind a deterministic layer and configured to fail closed, it is a second net rather than the only one. It needs no setup from the user, and its policy can be updated server-side as attack patterns move. Concede all of that. The question is where the boundary is standing when the attack is one the model has not seen.

Where an in-band boundary gives way

Four problems, and they compound.

It cannot be audited. An allowlist and a firewall rule can be read line by line and diffed in review. What a model will allow cannot be enumerated, unit-tested, or diffed. A boundary that can only be trusted is an estimate the operator is forced to accept.

The judge shares the blast radius. This is Zechner's point, and it survives the more careful implementation. Once the agent can execute code and reach the network, a per-call judge living in that same domain is matching against inputs the domain can also shape. Injection crafted to read as benign passes it.

It is least reliable on exactly the inputs that define the threat. Novel out-of-distribution actions and adversarial injection are where a classifier is weakest, and they are the whole reason for the gate. Anthropic's published numbers make the size of the gap concrete: on real overeager actions (n=52), the full auto-mode pipeline has a 0.4% false-positive rate and a 17% false-negative rate. Roughly one in six actions that exceeded what the user asked went through. Anthropic ships auto mode opt-in and keeps human approval as the standard default, which is a reasonable read of its own measurement.

It relocates the reflexive approval it was meant to fix. The reason operators reach for the flag is that approvers approve on reflex. Anthropic's own telemetry puts prompt approval at 93% by default, which is the approval-fatigue problem stated as a number. A model approver approves far faster than a human and with no person on the hook when it waves the wrong action through. The classifier lowers the human's attention cost to zero, which is the same dynamic that produced the 93%, now automated.

There is a cost term as well. Every reviewed call spawns extra inference, so the boundary adds latency and tokens, and it is nondeterministic: the same command can be judged two ways in two sessions. A firewall rule costs nothing per call and decides the same way every time.

Moving the boundary out-of-band

"Skip permissions safely" stops being a contradiction once the boundary is out-of-band. Isolation escalates through four levels: allowlists (cheap, advisory), OS sandbox, devcontainer with egress control, and disposable VM. The load-bearing rung is isolation rather than the allowlist, because an allowlist has the classifier's weakness, enumerating creative badness, while isolation does not try to recognize the bad action at all. It removes the capability the action would need.

Minimal YOLO cell: one repo, no creds, package registries only
docker run -it --rm \
  --name yolo-cell \
  -v "$PWD:/work" -w /work \
  --tmpfs /tmp \
  --cap-drop=ALL --security-opt no-new-privileges \
  --memory=8g --pids-limit=512 \
  --network yolo-egress \
  yolo-image claude --dangerously-skip-permissions

Here yolo-egress is a network whose only route is a proxy that allowlists the package registries and the model API. Anthropic's reference devcontainer already has this shape: an init firewall that default-denies and pinholes npm, PyPI, GitHub, and the API endpoint. Copying it is faster than rebuilding the egress rules by hand. The level-by-level recipe is covered in the post on what an unattended agent can actually do; the part that carries most of the safety is two assets. Give the cell exactly one credential, a scoped and revocable model-API key, and keep SSH keys, cloud creds, and .env files outside it. Let the agent commit but not push, so the work comes back as a diff that gets reviewed and pushed from a machine the operator trusts.

This is prevention rather than detection, and the two have different failure modes. Classifying rm -rf / correctly stops mattering once the box is disposable and the only thing that leaves is a diff. A classifier has to be right on every call; an isolation boundary has to be built once and then holds for calls it has never seen.

Where a classifier still helps

The concession is genuine. When isolation truly is not on the table, a fail-closed classifier beats an open door, and Codex's ordering, deterministic policy first and the model second, is the right shape for one. Run behind isolation, a classifier is a useful second layer: it can catch a mistake inside the wall without being the wall.

As the primary boundary it inherits the agent's blind spots, and the 17% figure is what that inheritance costs. The recommendations that follow from the comparison:

  • Put the boundary under the agent, not inside it. Isolation is the load-bearing layer; a classifier is a net.
  • If a classifier runs, run it behind isolation. Codex's deterministic-policy-first ordering is the model to copy; a model judge should never be the only gate.
  • Isolate the two assets that outlive the session: credentials and push access.
  • Take the work back as a reviewable diff. A boundary that can be read is testable in a way a learned one is not.