When headlines say an AI agent "escaped its sandbox"... what wall did it pass?
Some sandboxes are walls. Some are just curtains.
Containers, seccomp, gVisor, Firecracker, Kata, WebAssembly, V8 isolates. They all sort into one ladder, with one question:
How much of the host kernel can the code reach?
And there's one door none of them close. We'll get there.
Why sandbox at all?
Your agent writes code, then runs it. But who really wrote it?
Treat agent code like code from a stranger. Because it might be.
The building and its plumbing: the kernel
Here's the building. Every program lives in its own apartment.
Down in the basement is the kernel: the plumbing every apartment shares.
Open a file, send a packet? You ask the kernel. That request is a syscall. Linux has hundreds of them, and every one is a pipe into the basement.
One bug in that plumbing, and a tenant can flood the whole building.
Containers: a locked room
So what's a container? A locked room in this same building.
- Namespaces control what you can see: your own processes, files and network.
- cgroups control how much you can use: CPU, memory, how many processes.
On a Mac or Windows, Docker runs a Linux VM, so the shared kernel is that VM's.
seccomp: the list of taps
Next layer: seccomp, a list of taps you're allowed to turn.
It's a tiny filter program that checks each syscall's number and arguments, and answers allow, errno or kill:
read allow
write allow
mount blocked
ptrace blocked
kexec_load blocked
openat allow
But the kernel's own docs say it plainly: syscall filtering isn't a sandbox.
Is a Docker container a sandbox?
Not on its own.
In January 2024, a bug in runc, the tool that starts containers, let them reach the host's files. That's CVE-2024-21626. A full container escape.
And that wasn't even the kernel.
The classic own-goal: docker.sock
Mounting the Docker socket into the container:
docker run -v /var/run/docker.sock:/var/run/docker.sock agent
Whoever controls that socket controls the Docker daemon, and the daemon runs as root.
Volumes only, a separate network? Better. But it's still the same kernel.
So the people saying "if it escaped, it wasn't a sandbox"? They're right. If it shares a kernel, it's a curtain, not a wall.
gVisor: hire a concierge
So how do you keep code away from the pipes? Hire a concierge.
That's gVisor: its Sentry is a kernel, written in Go, running in user space. Your code makes a syscall, and the Sentry answers it itself.
It only makes a small, filtered set of host calls. Files go through a helper, the Gofer.
What does the concierge cost? Every syscall takes a detour, so syscall-heavy work slows down. And some programs expect plumbing the Sentry doesn't provide, so compatibility drops.
MicroVMs: your own tiny house
Still nervous about sharing a building? Then move out. Get your own tiny house.
A microVM runs your code on its own guest kernel, with its own plumbing. Firecracker is the VMM, the virtual machine monitor, built on KVM, the hypervisor inside Linux.
The house still has one metered service line into the building's basement: KVM. To escape, code has to get past its own kernel, and then break the VMM or KVM too.
Share a folder in, though, and you've cut a door in that wall.
Isn't a VM slow?
Firecracker's spec says the guest reaches init within 125 ms:
[0.000] InstanceStart
[0.003] guest kernel boots...
[0.125] /sbin/init
/dev/kvm: required
And the VMM itself adds at most about 5 MB of memory. Low-powered machine? The overhead is tiny, if it has KVM. The guest's own memory is the real bill.
Many sandboxes at once? Fine. They only talk to each other if you wire up a network.
That's why platforms like E2B describe a sandbox as a Linux VM made on demand. Even Docker's own agent product, Docker Sandboxes, runs each agent in its own microVM.
Kata Containers: a container's front door
But your tools speak containers, not VMs. So Kata puts a lightweight VM behind the container interface.
Same front door as an apartment, but a tiny house behind it. Your container tools never know they're running a VM.
WebAssembly and V8 isolates: the glovebox
Now flip it. Picture a sealed glovebox in the lobby. You work through the gloves you're handed, and nothing else.
A WebAssembly module's memory is bounds-checked. Step outside it, and the module traps: no pipes to the basement at all.
Same idea for JavaScript. V8 is Chrome's JavaScript engine, and an isolate is one sealed instance of it. It gets its own memory and only the APIs it's handed. Cloudflare Workers run thousands per process. Cloudflare says they start about a hundred times faster than a containerized Node process, using a tenth of the memory.
The glovebox catch
So the glovebox is the strongest rung, right? Not so fast.
Now the wall is the runtime itself, and runtimes have bugs. Break one, and you're a normal host process. In 2024, V8's team said even its newest sandbox wasn't yet a strong boundary.
Side channels, timing the shared CPU, still work too. Even between tiny houses.
The ladder
Sorted by how much host kernel the code can reach:
| Rung | Analogy | What the code reaches |
|---|---|---|
| Container + seccomp | locked room, list of taps | the shared kernel, filtered by seccomp |
| gVisor | the concierge | the Sentry, which makes a small, filtered set of host calls |
| Firecracker microVM / Kata | your own tiny house | only its VMM and the KVM under it |
| Wasm / V8 isolates | the glovebox | nothing but their imports |
And every wall here is software, so any rung can have bugs.
Which rung should you pick?
- Your own agent on your own repo? A container-level sandbox is the floor. An injected command's easy win is your network, not a kernel exploit, and the next rule shuts that.
- Running strangers' code, or anything multi-tenant? Give it its own kernel: gVisor or a microVM.
The door no rung closes: the network
So what if your agent sat in a perfect microVM, holding real API keys, with open internet?
Without network isolation, one injected instruction and one outbound request, and your keys are gone.
Every wall held. The code just walked out the front door.
Egress: the mailroom
Allowlist destinations: a mailroom that only delivers to addresses on the list.
ALLOWLIST
pypi.org
github.com
everything else: DENIED
Can it still leak? If it reads your data and can reach an allowed host, yes. So keep that list as short as the job allows, and lock down DNS too.
Secrets: keep the master keys out of the house
The sandbox gets a placeholder, and the mailroom attaches the real credential on the way out:
inside the sandbox: Authorization: Bearer PLACEHOLDER
after the mailroom: Authorization: Bearer sk-live-...
Injected code can read that placeholder all day. Off the box, it's worthless. It can still use the key through the mailroom, so keep the allowlist short.
Agent code is untrusted on your laptop too: review it, or run it sandboxed.
A real example: Claude Code's sandbox
Does anyone build it this way? Here's one example: Claude Code's sandbox.
It's off by default. You turn it on with:
/sandbox
On Linux it uses bubblewrap, the same namespaces trick a container uses. On macOS, Seatbelt, Apple's built-in sandbox.
Commands get no direct route out. A host proxy checks every domain against an allowlist that starts empty. Set up masking, and the proxy swaps a placeholder key for the real one.
Its own docs say it reduces risk, but isn't a complete isolation boundary. For strangers' code, climb.
Recap
One building. The kernel is the shared plumbing. A container is a locked room. seccomp is the list of taps. gVisor is the concierge. A microVM is your own tiny house, and Kata gives it a container's front door. Wasm and isolates are the glovebox. And the mailroom guards the one door no wall closes.
So did that agent escape its sandbox? Ask two things: was it a wall, or a curtain? And which door was open?
Which rung is your agent on right now? Tell me in the comments.
More in this series: AI agent identity with SPIFFE and SPIRE, Pi 1.0 and Pi Durable, AI reverse engineering.
This is the written version of a 10-minute animated explainer on RuntimeStack. Sources: syscalls(2), namespaces(7), cgroups(7), seccomp BPF, Red Hat RHSB-2024-001, CVE-2024-21626, Dirty Pipe, Docker Engine security, Docker Sandboxes architecture, Docker Desktop VMM, gVisor docs, gVisor platforms, Firecracker README, Firecracker specification, Firecracker getting started, Firecracker (NSDI '20), Kata Containers, Kata hypervisors, WebAssembly security, How Workers works, Workers security model, The V8 Sandbox, Claude Code sandboxing, E2B docs, OWASP LLM01.






Top comments (0)