Sandboxing & Isolation
The Execution Boundary
An agent that writes and runs code has turned model output into executable instructions, and every document it reads, page it fetches and tool result it receives is a potential source of those instructions. Sandboxing is the assumption that the agent will eventually be persuaded to do something harmful, and the containment of what that costs. It is a separate control from guardrails, which try to stop the intent, and it holds when they fail.
Isolation Boundaries
Five levels, in order of strength. Each one buys a smaller escape surface and costs startup time, operational complexity, or both.
Stripped builtins, import allowlists, AST inspection before execution. Cheap and instant, and the weakest option available. Any bug in the restriction logic is a full escape into the host process, and the escape techniques are widely published for every major language.
The process runs normally but the kernel refuses syscalls outside a declared set. Blocks whole capability classes at a level the workload cannot argue with. Requires knowing which syscalls the workload legitimately needs, which is difficult when the workload is arbitrary generated code.
The common default, giving separate filesystem, process and network views plus resource caps. Strong enough for untrusted code from a known source, and the shared kernel remains a single boundary between the sandbox and everything else on the host.
A hardware or intercepted virtualisation boundary rather than a shared kernel, at close to container startup times. The current default for running genuinely untrusted generated code at scale, and what most hosted code-execution products are built on.
The blast radius is bounded by the account, not the process. Reserved for agents holding real credentials or acting on production systems, where the question is not whether code escapes the sandbox but what it reaches once it does.
Capability Classes
"Sandboxed" is not a single property. Each capability is granted or withheld separately, and a boundary that stops one class often does nothing about another.
| Capability | Concrete Risk | Control | Commonly Missed |
|---|---|---|---|
| Filesystem | Reading credentials, SSH keys and other tenants' data; writing to startup paths for persistence | Read-only root, a writable scratch mount, no host bind mounts | Mounted secrets |
| Network egress | Exfiltrating anything the agent has read to any host that will accept it | Deny by default, allowlist by host, enforced at a proxy outside the sandbox | Left fully open |
| Process spawn | Shelling out to reach tools the sandbox policy never considered | Block exec, or allowlist binaries and drop the ability to spawn shells | Subprocess allowed |
| Credentials | Environment variables and instance metadata inherited straight into the sandbox | Empty environment, no metadata route, short-lived scoped tokens passed explicitly | Inherited env |
| Resources | CPU, memory or disk exhaustion taking out the host or the co-tenants | Hard cgroup limits, wall-clock timeout, process and file descriptor caps | No wall-clock cap |
| Time and entropy | Non-determinism that makes runs unreproducible and incidents hard to reconstruct | Pin the clock and seed where reproducibility matters | Rarely considered |
Network Egress
Filesystem and process isolation get attention because they are visible in the container config. Network egress is usually left open because the agent needs to reach a model API and a few tools, and "a few tools" quietly becomes the whole internet. Every exfiltration path below survives filesystem isolation completely.
The obvious path, and the one an allowlist actually catches. Worth stating because it is often the only one anyone models.
Control: Host allowlist at an egress proxy, with TLS interception if payload inspection is required.
Data encoded into hostnames that are looked up but never connected to. Survives an HTTP allowlist entirely, because resolution happens before any connection policy applies.
Control: Route DNS through a resolver that logs and rate-limits, and refuse resolution of names outside the allowlist.
The allowlist permits a package registry, a paste service or a git host, and any of those will happily store data on the agent's behalf. The connection looks entirely legitimate.
Control: Allowlist by host and method. A registry needs GET, not PUT.
The agent emits markdown containing an image URL with data in the query string. Nothing leaves the sandbox; the exfiltration happens in the browser that renders the reply.
Control: Sanitise generated output before rendering, and treat model output as untrusted content downstream.
The workable default is deny-by-default egress with an allowlist of hosts, enforced at a proxy rather than inside the sandbox, so the agent cannot rewrite its own rules. See Agentic Zero Trust for the wider bidirectional model.
Lifecycle and State
How long a sandbox lives determines both what an attacker can accumulate inside it and how much work the agent has to redo. The three models trade cleanly against each other.
| Model | Behaviour | Suits | Contamination Risk |
|---|---|---|---|
| Ephemeral | Fresh sandbox per execution, destroyed immediately afterwards | Untrusted code, multi-tenant workloads, anything user-triggered | None |
| Session-scoped | One sandbox per conversation or task, destroyed when it ends | Iterative work where files and installed packages must persist across turns | Within session |
| Persistent workspace | Long-lived environment reattached across sessions | Long-running projects with expensive setup | Accumulates |
Failure Modes
The sandbox is correctly isolated but starts with the parent process environment, so cloud credentials, API keys and tokens are present from the first instruction. The isolation is real and irrelevant.
Fix: Start from an empty environment. Pass only short-lived, narrowly scoped tokens, and block the instance metadata route explicitly.
Generated code is sandboxed, but the agent's tools execute in the host process. An attacker skips the sandbox entirely and asks the agent to use a tool instead.
Fix: Apply the same boundary to tool execution. If a tool must run privileged, treat its arguments as untrusted input and gate it separately.
Filesystem and process isolation are configured carefully and the network is left open, so anything the agent reads can be sent anywhere. The most common gap in otherwise well-built sandboxes.
Fix: Deny by default and allowlist by host, enforced outside the sandbox so the agent cannot alter the policy it runs under.
A pooled or reused sandbox keeps state between runs, letting one session plant something the next one executes. Reuse exists to avoid cold starts and quietly reintroduces contamination.
Fix: Reset from a known image rather than cleaning in place. Pool the warm base, never the used instance.
A command is approved by a human or a policy check, then modified before it runs, or the file it targets changes underneath it. The approval covered something that no longer exists.
Fix: Bind the approval to the exact command and its arguments, and re-validate at execution rather than at request time.
Generated code loops or allocates without limit. Without a wall-clock cap the sandbox survives while the budget does not, and co-tenants degrade first.
Fix: Hard cgroup limits plus a wall-clock timeout. Treat the timeout as mandatory rather than as a tuning parameter.
Choosing an Isolation Level
| Situation | Why It Matters | Level |
|---|---|---|
| Model-generated code, public users | Arbitrary untrusted code with an incentive for someone to attack it | MicroVM |
| Internal developer tooling | Authenticated known users, and the blast radius is already their own access | Container |
| Agent holds production credentials | Escape is not the risk; what the credentials reach afterwards is | Account separation |
| Evaluating simple expressions | A narrow grammar with no need for a filesystem or a network | Interpreter restriction |
| Shared multi-tenant execution | One tenant reaching another is the failure that ends the product | MicroVM, ephemeral |
| No isolation at all | Defensible only when the agent cannot execute, write or fetch anything | Verify that claim |
Related: Agentic Zero Trust for treating the agent as an untrusted principal in both directions, AI Security for the injection routes that make containment necessary, AIUC-1 for how isolation is evidenced under certification, Multi-Tenancy for tenant isolation when sandboxes are shared, and Container and Orchestration for the runtime layer underneath.
