Skip to content
Markdown

Agent sandboxing and isolation

Scope: running model-generated code and tool calls without trusting them. An agent that executes code is running untrusted input by definition, so the question is which isolation boundary matches the trust level. Covers the isolation spectrum (process, container, syscall interception, microVM), where container defaults hold and where they do not, and the agent-specific pattern of reversible workspaces. Enforces the threat model and is gated by the control plane; reuses platform isolation from security and multi-tenancy.

This page describes defensive isolation. CVEs are referenced for context; configs are reference-only.

flowchart LR
  TRUST["Trust level of code"] --> PROC["Process<br/>(no isolation)"]
  PROC --> CONT["Container<br/>(namespaces, seccomp, caps, MAC)"]
  CONT --> GV["gVisor<br/>(syscall interception)"]
  GV --> VM["Firecracker / Kata<br/>(microVM)"]
  CONT -.->|"trusted workloads"| OKT["Adequate"]
  GV -.->|"untrusted code"| OKU["Adequate"]
  VM -.->|"untrusted multi-tenant"| OKU

Overview

The single worst sandboxing mistake is running agent-generated code on the host. Everything else is choosing how strong the boundary needs to be. Container defaults are stronger than commonly assumed for trusted workloads, but for untrusted multi-tenant code they are insufficient, and the "advanced" container features are one misconfiguration away from host compromise. When the code is genuinely untrusted, move up the spectrum to syscall interception or a virtual-machine boundary.1

Core knowledge

The isolation spectrum

  • Process: no isolation. Never for agent-generated code.
  • Container: Linux namespaces plus a seccomp profile, dropped capabilities, and a mandatory-access-control profile (AppArmor or SELinux). The right answer for trusted first-party workloads.
  • gVisor: a user-space kernel intercepts syscalls, so the container talks to a sandbox rather than the host kernel directly. Its Sentry needs on the order of 53 host syscalls (68 with networking) against roughly 350 for a normal container, an eighty-percent cut in kernel attack surface.2
  • microVM (Firecracker, Kata): a real but minimal VM boundary. Firecracker boots in about 125 ms with a few megabytes of overhead per microVM and is around 50k lines of Rust, against roughly two million lines of C for a general-purpose emulator, a much smaller and more auditable trusted computing base.3

Match the boundary to the trust level: containers for trusted code, gVisor or a microVM for untrusted or multi-tenant code.

Why container defaults are not enough for untrusted code

Container isolation rests on six mechanisms: mount namespaces with OverlayFS, FUSE, mount propagation modes, mandatory access control, seccomp, and cgroups. The defaults enforce in a useful order (seccomp, then capabilities, then MAC, then the kernel), and a default seccomp profile already blocks dozens of dangerous syscalls. The danger is in the features people turn on: a mounted Docker socket is a direct path to host root, bidirectional mount propagation plus an over-broad capability lets a container shadow host paths, and OverlayFS bugs have repeatedly yielded root.1

The CVE record makes the point. CVE-2023-0386 (an OverlayFS privilege escalation) reached the CISA Known Exploited Vulnerabilities catalog; the GameOver(lay) pair (CVE-2023-2640 and CVE-2023-32629) affected a large share of Ubuntu cloud workloads; and a runc flaw allowed an AppArmor bypass via a symlinked path. The operating takeaway is blunt: the shared kernel is not a security boundary for untrusted code.4

Harden what you do run

  • Run rootless where possible, drop all capabilities and add back only what is needed, and keep a restrictive seccomp and MAC profile.
  • Apply Kubernetes Pod Security Standards (the restricted profile) and reject privileged GPU containers.
  • Add Landlock for unprivileged, process-scoped filesystem restriction inside the sandbox.
  • Cut egress by default; an exfiltration channel is half of the lethal trifecta.

Reversible workspaces for agents

Beyond confining the blast radius, agents benefit from making actions undoable. Running each agent or sub-agent in a reversible workspace, for example a git worktree per task, means its filesystem changes can be inspected and discarded rather than trusted. Combined with a per-call sandbox for code execution and a hard time limit, this turns "the agent ran some code" from an irreversible event into a transaction the control plane can approve, audit, or roll back.5

The sandbox is one component of a runtime

Isolation is the security question. The engineering question is larger, because an agent runtime is six things, not one: a compute substrate (container, microVM, or VM), a filesystem with snapshot and rollback semantics, a tool surface (shell, code interpreter, browser, MCP servers), a network boundary defining what the agent can reach, a state model for persistence across turns, episodes, and users, and a lifecycle controller that creates and destroys environments. Choosing a sandbox at prototype time settles all six by accident, and the ones that are wrong surface as production incompatibility months later.6

Startup cost is the property that ties isolation strength to workload economics, because it is paid per session and per rollout rather than once.

Primitive Isolation model Cold start Fits
Linux container Shared kernel, namespaces, cgroups, seccomp around 100 ms Trusted, internal CI
gVisor User-space kernel intercepting syscalls Container-class Defense in depth, GPU virtualization
Kata Containers Lightweight VM per pod, OCI-compatible A few hundred ms Multi-tenant Kubernetes
Firecracker KVM microVM, small Rust VMM around 125 ms boot, sub-second from snapshot Untrusted, high density
V8 isolates Per-tenant heap in one process Sub-millisecond JavaScript only

At training scale the arithmetic bites: five seconds of cold start across ten thousand rollouts is real money and real wall-clock. In production a session-scoped agent amortises the same cost over minutes of work and barely notices it. And once a session carries a full dependency stack, the ceiling moves entirely: an agent's productivity is bounded by how fast its runtime comes up, not by the model's tokens per second.6

Serverless request-response platforms with strict execution limits and no snapshot model are the wrong substrate for this regardless of their isolation strength, because the state model and lifecycle controller are missing.

Training and production runtimes diverge, and the divergence is a defect

The runtime an agent is trained in and the runtime it is deployed in want opposite properties, and a policy learned against one silently encodes the quirks of that one.6

Dimension Training Production
Concurrency Thousands of parallel rollouts, bursty One session per user, steady state
Cold start Critical Forgivable
State model Fork, branch, replay, snapshot Durable, auditable, per user
Network Offline or recorded Live internet, real APIs
Failure handling Drop the rollout, sample more Retry, degrade, or escalate
Lifetime Seconds to minutes Minutes to hours, or session-pinned
Determinism Required Often counterproductive

Three ways to close the gap, in increasing order of engineering effort and decreasing order of lock-in. Co-locate: use one provider for both and accept the dependency. Contract: define a versioned runtime interface (shell surface, tool set, latencies, failure modes) and enforce it on both sides, which is the same discipline as holding the substrate fixed for a harness ablation. Inject production noise into training: deliberately fail 5 to 10% of tool calls during rollouts so the policy learns recovery rather than learning that tools always work.6

The failure this prevents is the expensive one. A runtime migration undertaken after the fact is unbounded work, because nobody can predict which learned behaviours depend on the old environment until they break.

Don't-miss checklist

  • Never execute agent-generated code on the host; isolate every code path.
  • Containers for trusted code; gVisor or a microVM for untrusted or multi-tenant code.
  • Never mount the container runtime socket into an agent sandbox.
  • Rootless, least-capability, seccomp and MAC profiles on; Pod Security Standards restricted.
  • Default-deny egress; time-limit and resource-cap every execution.
  • Run agents in reversible workspaces so filesystem changes can be discarded.

Failure modes

  • Host execution. Code runs outside any sandbox; one malicious tool call owns the machine.
  • Socket mount. The runtime socket is exposed to the agent, granting host root.
  • Propagation misconfig. Bidirectional mounts plus a broad capability let the container reach host paths.
  • Shared-kernel trust. Untrusted code on a plain container; a kernel CVE escapes to the host.
  • Open egress. The sandbox can reach the internet, completing an exfiltration path.
  • Irreversible actions. No reversible workspace; a bad action cannot be rolled back.
  • Runtime shift. A policy trained against a permissive, deterministic, offline runtime meets a scoped, noisy, live one and behaves differently, with no trace explaining why.
  • Cold start as the real bottleneck. Session startup dominates end-to-end latency once the environment carries a dependency stack, and no amount of model throughput compensates.
  • Prototype substrate shipped to production. The sandbox chosen for a demo settles the state model and lifecycle controller too, and changing it later is a migration nobody scoped.

Open questions & validation

  • gVisor and microVMs add latency and some compatibility limits; measure the overhead on the target tool workload.
  • Validate the sandbox by attempting the known escape classes (socket, propagation, OverlayFS) against it in a test environment.
  • Confidential-computing isolation for agent workloads on shared GPUs is an evolving option (security and multi-tenancy).

References

  • gVisor (application kernel for containers): https://gvisor.dev/
  • Firecracker microVM: https://firecracker-microvm.github.io/
  • Firecracker: Lightweight Virtualization for Serverless Applications (NSDI 2020): https://www.usenix.org/conference/nsdi20/presentation/agache
  • Kata Containers: https://katacontainers.io/
  • Linux seccomp BPF: https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html
  • Landlock LSM: https://landlock.io/
  • Kubernetes Pod Security Standards: https://kubernetes.io/docs/concepts/security/pod-security-standards/
  • CVE-2023-0386 (OverlayFS privilege escalation): https://nvd.nist.gov/vuln/detail/CVE-2023-0386
  • CVE-2023-2640 (GameOver(lay)): https://nvd.nist.gov/vuln/detail/CVE-2023-2640
  • Lee, Hidden Technical Debt of AI Systems: Agent Runtime: https://leehanchung.github.io/blogs/2026/04/24/hidden-technical-debt-agent-runtime/
  • Sculley et al., Hidden Technical Debt in Machine Learning Systems (NeurIPS 2015): https://papers.nips.cc/paper/2015/hash/86df7dcfd896fcaf2674f757a2463eba-Abstract.html

Related: Agent threat model · Prompt-injection defense · Policy, guardrails & governance · Orchestration & control plane · Security & multi-tenancy (platform) · Agentic systems


  1. Container defaults protect trusted workloads adequately but are insufficient for untrusted multi-tenant code; the six mechanisms are mount namespaces with OverlayFS, FUSE, mount propagation, MAC, seccomp, and cgroups, enforced seccomp-then-capabilities-then-MAC-then-kernel. The high-risk features are runtime-socket mounts, bidirectional mount propagation with broad capabilities, and OverlayFS bugs. 

  2. gVisor's Sentry intercepts syscalls in user space and needs roughly 53 host syscalls (68 with networking) versus about 350 for a normal container, around an eighty-percent reduction in kernel attack surface. 

  3. Firecracker boots in about 125 ms with a few megabytes per microVM and is roughly 50k lines of Rust, a far smaller trusted computing base than a general-purpose emulator. 

  4. CVE-2023-0386 (OverlayFS) reached the CISA KEV catalog; GameOver(lay) (CVE-2023-2640 / CVE-2023-32629) affected a large share of Ubuntu cloud workloads; a runc flaw enabled an AppArmor bypass via a symlinked path. The shared kernel is not a boundary for untrusted code. 

  5. Running each agent or sub-agent in a reversible workspace (for example a git worktree per task), with a per-call execution sandbox and a hard time limit, makes filesystem changes inspectable and discardable rather than trusted. 

  6. Lee, "Hidden Technical Debt of AI Systems: Agent Runtime" (2026-04-24), which extends the Sculley et al. (2015) argument that supporting infrastructure, not the model, is where the debt accumulates. Source of the six-component runtime definition, the cold-start comparison, the training-versus-production dimension table, and the three resolution paths (co-locate, versioned runtime contract, inject 5 to 10% tool errors during training). Cold-start figures are order-of-magnitude and vendor-dependent; the Firecracker boot figure agrees with the NSDI 2020 paper cited above. Sandbox-as-a-service vendor characteristics drift quickly and are deliberately not tabulated here.