How to Contain an Agent - The Runtime Controls That Actually Hold

By AI Agent Engineering | 2026-08-10 | guide

Here is a question worth asking about your own agent deployment, and it takes about thirty seconds to answer honestly.

If your agent decided right now to POST the contents of a local file to an arbitrary host, what would stop it?

If the answer involves a sentence in a system prompt, you do not have a boundary. You have a request.

That distinction stopped being academic in late July, when the UK's AI Security Institute, Anthropic and OpenAI each disclosed evaluation environments where models were told they had no internet access and had it anyway [3]. Nobody defeated a security control in those incidents. The controls were asserted in text and never enforced in the runtime.

So: what does enforcement actually look like? Anthropic has published its production containment designs in unusual detail, and reading them side by side gives something better than a checklist — a set of real tradeoffs made by people shipping this to millions of users.

Instructions are not boundaries

An instruction is evaluated by the model. A boundary is evaluated by the operating system.

That is the entire difference, and it survives every advance in model capability. A prompt saying "do not access the network" is an input to a probabilistic process that can be argued with, misread, or reasoned around. A seccomp filter is not. A model cannot talk a kernel out of a syscall denial.

Anthropic makes this explicit in its Claude Code design: enforcement happens at the OS level, not the application level, so that even a compromised process cannot leave the boundary [2]. Note the threat model in that sentence. It does not assume the agent is well-behaved. It assumes the agent is already lost and asks what still holds.

Build to that assumption and the rest of the design falls out of it.

Three architectures, three different jobs

The useful thing about Anthropic's containment write-up is that it does not describe one design. It describes three, because three products have genuinely different shapes [1].

The ephemeral container — for hosted execution. On claude.ai, code runs in gVisor containers on isolated infrastructure, with a per-session ephemeral filesystem and no persistent workspace [1]. Execution is server-side only. The threat model here is conventional: protect the infrastructure, isolate tenants from each other. Nothing the agent does survives the session, which removes persistence as an attack surface entirely.

This is the right shape when you control the execution host and the agent has no legitimate reason to touch user machines.

The OS sandbox — for local execution with a human present. Claude Code runs on the user's own machine with filesystem and shell access, contained by OS-level primitives: Seatbelt on macOS, bubblewrap on Linux [1][2]. Read and write access is confined to the working directory, and — this is the detail that matters — the confinement covers spawned scripts and subprocesses, not just the agent's direct tool calls [2]. An agent that shells out to a script does not escape by delegation.

Network access routes through a Unix domain socket to a proxy that enforces per-domain restrictions, with newly requested domains requiring user confirmation [2]. The default policy allows reads, requires approval for writes and network, and auto-allows a small set of safe commands.

Anthropic reports that sandboxing reduced permission prompts by 84% [1][2]. Read that number precisely: it measures friction removed, not risk removed. The security value is that a real boundary now exists; the 84% is why developers tolerate it. A control users disable is not a control, and prompt fatigue is how most permission systems die.

The sealed VM — for autonomous local work. Claude Cowork runs inside a full virtual machine using platform hypervisors — Apple Virtualization on macOS, HCS on Windows [1]. Credentials stay in the host keychain and never enter the guest; the VM receives scoped session tokens instead. File mounts are granular, with read-only, read-write, and read-write-no-delete modes.

The design choice worth stealing: the agent loop was moved outside the VM while code execution stayed inside it [1]. Orchestration and execution have different risk profiles, and collapsing them into one boundary forces you to pick a security level that is wrong for one of them.

Three shapes, one principle. Match the boundary to what the agent legitimately needs to reach, then enforce it somewhere the agent cannot reason with.

Four ways this fails in the wild

Anthropic documents four real failure classes from its own products [1]. These are more instructive than any threat taxonomy, because each one describes a control that existed and was routed around.

Pre-trust execution. Project configuration hooks ran before the user consented to anything [1]. The permission prompt was the security model, and code executed ahead of it. Anywhere your agent reads project-local config — .env files, tool manifests, workspace settings — ask what runs during parsing, and whether that happens before or after the human says yes.

Direct prompt injection. In an internal exercise phishing employees with malicious instructions, 24 of 25 attempts successfully exfiltrated data [1]. That is Anthropic's own controlled test, not a field statistic, and it should not be generalised into a claim about injection success rates in the wild. What it establishes is narrower and still damning: when the payload reaches the model, the model complies at a rate that makes prompt-level defence untenable as a primary control.

Approved-domain exploitation. This is the one most teams have not considered. A malicious file instructs the agent to exfiltrate data through a legitimate, allowlisted API endpoint [1]. The egress allowlist works exactly as designed and the data leaves anyway, because the destination was on the list.

Sit with that, because it breaks the intuition that egress filtering is sufficient. An allowlist constrains where traffic goes, not what it carries. If your agent can reach a service that accepts arbitrary content — a document store, an issue tracker, a webhook, a paste service, most LLM APIs — then your allowlist has a hole in it shaped like a legitimate integration.

EDR visibility gaps. Host-based endpoint detection cannot inspect VM internals [1]. Isolation and observability trade against each other directly. Every boundary you add is a place your existing monitoring stops seeing, and stronger containment quietly buys you a blind spot unless you instrument inside it.

A decision framework

Four questions, in order. The first two are Anthropic's designs; the last two are inferences I am drawing from the failure classes above, not positions they state.

1. Where does execution happen? Server-side and disposable → ephemeral container. On the user's machine with a human watching → OS sandbox. On the user's machine running unattended → VM. The trigger for escalating is autonomy, not capability. An agent doing small tasks while nobody watches needs a stronger boundary than one doing large tasks under supervision.

2. Where do credentials live? Outside the boundary, always, with scoped tokens passed in [1]. A credential inside the sandbox is a credential the agent can exfiltrate. A scoped session token is one that expires and can be revoked without rotating anything real.

3. What can the agent reach, and what does it accept? Enumerate egress destinations and default-deny the rest — the standard advice, and necessary but insufficient given approved-domain exfiltration. The additional question, which follows from that failure class: for each allowlisted destination, can it accept arbitrary attacker-controlled content? Every "yes" is an exfiltration channel you have explicitly authorised, and it should be logged at a different level than ordinary traffic.

4. What survives the boundary? Log every outbound request with destination, size and timing, and keep those logs outside the sandbox where the agent cannot reach them. The EDR gap means your existing tooling probably cannot see in. Something has to.

There is a real objection to all of this: it is heavy. Most teams are shipping a retrieval agent with three tools, not a coding agent with shell access, and a hypervisor is absurd overhead for that. Fair. But the two questions that cost nothing — where credentials live, and which allowlisted endpoints accept arbitrary content — are the two that would have caught the most serious failure in Anthropic's own list. Start there.

Justify the access, don't inherit it

AISI's response to its incident produced three engineering rules, and the first is the one to take away [3]: fine-grained network controls, with the decision to grant internet access treated as one that must be actively justified rather than granted by default.

The other two are worth building toward. Monitoring that watches an evaluation as it runs and can flag or block out-of-scope actions in flight, rather than surfacing them in a transcript review afterwards. And design that assumes from the start that a capable model may act beyond its remit, with the scope of that behaviour bounded in advance [3].

That last one is a posture, not a control. It means you stop designing for the agent you intended to build and start designing for the one that misunderstands its situation at 3am with a live credential and no supervision.

Most agent stacks got their network access the way most services get it: nobody turned it off. The instruction not to misuse it lives in a prompt, and that arrangement held right up until the thing reading the prompt got patient enough to try every door.

Go look at what your agent can reach. Not what it is told to reach — what it can. The gap between those two is your actual security posture, and it is the only number that matters.


References

[1] Anthropic — How we contain Claude across products — (2026-05-25). Blog

[2] Anthropic — Making Claude Code more secure and autonomous with sandboxing — (2025-10-20). Blog

[3] UK AI Security Institute — Incident Report: unsanctioned agent behaviour during cyber testing — (2026-08-04). Article