🌏 中文版
Agent sandboxes usually take one of three forms: a plain container, gVisor, or a microVM (Kata Containers, Firecracker, and the like). All of them are called "isolation," but they separate things at different points. This post answers two questions: how many kernel boundaries does an agent's code have to cross to reach the host, and what do all three still share after it does?
It reads better after Where an Agent's Code Runs; this post covers its L1 container and L2 kernel boundary. Afterwards you should be able to tell, for a vulnerability advisory or an attack, which boundary it broke and how many are left before the host.
Containers: process isolation, shared kernel
Containers rely on Linux namespaces and cgroups. Docker's security documentation says namespaces keep processes in a container from seeing, and even less affecting, processes in other containers or on the host, and cgroups cap resources, mainly to stop resource-exhaustion attacks.
One Linux kernel enforces all of this, and the program in the container can issue system calls to that kernel directly. gVisor's security introduction is blunt about it: seccomp, namespaces, AppArmor and similar mechanisms shrink the attack surface, but the workload is "only one system call away from host compromise." Seccomp filters also have to be tuned per workload, and a program that needs a broad call such as ioctl or io_uring can make a safe filter very hard or impossible to write.
So a container's boundary sits at the system-call interface: if the host kernel has an exploitable bug there, the program gets to the host in one step.
gVisor: a user-space kernel in the middle
gVisor acts as the kernel itself. Per its documentation, the Sentry is a from-scratch Go reimplementation of Linux system calls, memory management, filesystems, the network stack, and more, and it "never passes through any system call to the host." A kernel feature gVisor has not reimplemented simply is not available to the sandboxed program. The Sentry itself makes only limited system calls to the host and is wrapped in seccomp, namespaces, and similar mechanisms; file operations that need more privilege go to the Gofer, a slightly more trusted companion process.
gVisor's security model places this next to virtual machines: in both, the application faces a stand-in interface, and the stand-in calls the host. The documentation's claim is that breaking out of gVisor requires exploiting the Sentry and the host kernel together, which share no code.
microVMs: another kernel, then a hypervisor
A microVM boots a lightweight virtual machine. In Kata Containers' architecture document, the runtime launches a hypervisor, which boots a VM from a dedicated guest kernel and image, and the container runs inside the VM. There is still a container inside the VM, to separate the workload from the VM environment itself.
Firecracker's design document starts from the threat model: each Firecracker process wraps exactly one microVM, every vCPU thread is treated as running malicious code from the moment it starts, and trust zones nest from the least trusted (vCPU threads) to the most trusted (the host), with seccomp and a jailer around the outside. By gVisor's description of virtual machines, the only way out of a VM is a VM exit, handled by the hypervisor.
Side by side: how many to cross, what is shared
Simplified. gVisor also has a Gofer process and several platforms, and a microVM's VMM runs as a host process; both are omitted.
| Container | gVisor | microVM | |
|---|---|---|---|
| Kernel the program faces directly | Host kernel | Sentry | Guest kernel |
| Still to cross before the host kernel | Nothing | The Sentry's limited calls | Hypervisor and device emulation |
| CPU cache shared with same-host sandboxes | Yes | Yes | Yes |
One example shows what "which boundary was broken" means. Kata's security advisory GHSA-wwj6-vghv-5p64 (CVE-2026-24834) describes a case with Cloud Hypervisor where a user in the container with CAP_MKNOD can rewrite the guest VM's root filesystem and end up root inside the VM. The advisory summary says "in my current understanding" the host and other containers or VMs on it are not affected, and its Impact line reads container to guest microVM escape, no escape to the host, no persistence of the overwritten image; the reporter adds that for arm64 with QEMU they did not verify whether a guest write could reach the image file. In this post's terms (our classification, not the advisory's wording): L1 broke, and in this case L2 held. OpenAI's October 23 article lists this CVE among the fixes it contributed back to Kata.
What all three still share
"Did not reach the host" does not mean "has nothing to do with the sandbox next door." Sandboxes on one host share CPU caches, memory bandwidth, and the host operating system's page cache.
A July 2026 preprint, Isolation Failure From Shared Storage, measured this on Docker, gVisor, Kata (with QEMU, Cloud Hypervisor, and Firecracker), and QEMU/KVM. It reports two things: whenever the I/O path exposes shared, host-cacheable file objects (OverlayFS layers, virtio-fs, loop devices backed by files), page-cache timing differences are measurable between sandboxes; with direct I/O or a dedicated block device, the signal weakens substantially or disappears. The authors say their WordPress case study is not an end-to-end attack demonstration, and that virtualization mostly adds latency and noise without removing the dependence.
Firecracker's production host setup guide carries a related warning: heavy storage writes can fill the host page cache quickly and create a backlog that slows other guests' I/O, which you manage with the jailer's resource limits and rate limiting.
The next post starts here: how two programs with no connection between them can send data using nothing but this "it got slower" signal.
How to choose
Answer three questions first; the answers decide whether to move toward microVMs and stricter tenant separation:
| Question | A container may be enough | Move toward microVM, one process per tenant |
|---|---|---|
| Who wrote the code? | You or your team | A model, or outside users |
| Who else is on the machine? | Only you | Other users' sandboxes |
| How is storage attached? | Doesn't matter | Whether cacheable host files are shared |
Firecracker's documentation strongly recommends that each Firecracker process correspond to a single tenant's workload; its unit is the process, not the whole host. Reserving the host for one tenant as well is more conservative than the documentation asks, and whether to go that far depends on your answers to the three questions above.
Something you can do tonight: run the following on a Linux host or VM and read what the kernel reports for each hardware vulnerability.
grep . /sys/devices/system/cpu/vulnerabilities/*
cat /sys/devices/system/cpu/smt/active
Each file reads Not affected, some Mitigation, or Vulnerable. Inside a virtual machine, some entries may say SMT Host state unknown; if you need to know the host's SMT (hyper-threading) state, ask the provider. Firecracker's documentation recommends disabling SMT in production deployments that need tenant separation.
Limits
- This post compares the number and position of boundaries, not how many bugs each has, and it cannot rank which is "most secure": what you are defending against decides what to choose.
- gVisor has several execution platforms with different details; this post follows the documentation's general description.
- The preprint is a lab timing measurement; it does not mean a usable attack already exists on real agent platforms.
References
- Docker Engine security — Docker Docs
- Introduction to gVisor security — gVisor
- Security Model — gVisor
- Kata Containers Architecture
- Firecracker Design
- Production Host Setup Recommendations — Firecracker
- Kata Container to Guest micro VM privilege escalation (GHSA-wwj6-vghv-5p64)
- Isolation Failure From Shared Storage (arXiv:2607.17518)
- Securing our frontier model training environment — OpenAI
- Where an Agent's Code Runs — this site