Security reality check
This chapter exists for the moment somebody says "it runs in a container, so it is isolated". Everything here is measured, published or on a vendor's own advisory page — not inferred from marketing.
The honest summary
- Shared-kernel containers are not a security boundary, and that is the position of the people who make the operating systems, not just of sceptics.
- Frontier models succeed at container escapes in the tens of percent on scenarios built from known CVEs and ordinary misconfigurations — and near zero on novel memory-corruption scenarios.
- Denylists fail against agents at rates between 69% and 98% in the published reviews.
- Indirect prompt injection against tool-using agents lands somewhere in the 10–30% band undefended, and jumps far higher under adaptive attacks.
- Network allowlists are not trust boundaries. A real agent escaped through an allowlisted proxy.
- A shipped product's sandbox was bypassed by a symlink, a denylist reading of a path, a config file that did not exist at startup, and its own ability to turn the sandbox off.
- Most real-world escapes are misconfiguration, not novel exploitation. That is the best news in this chapter, because misconfiguration is something you control.
- Genuinely hardened boundaries — microVMs, gVisor, WASM — collapse the escape rate to the noise floor in the same benchmarks.
- System-side controls work where model-side robustness does not: destination allowlists, capability isolation between the reader and the actor, and pre-execution authorisation each took measured attack success to around zero.
- Credential brokering removes an entire category of incident rather than reducing it. The agent cannot leak a key it never had.
- Every boundary in this guide is more likely to fail through a socket, a share, a helper or a bridge you left open than through a clever exploit.
What each boundary stops, measured
| Boundary | Accidents | Naive exfiltration | Adaptive exfiltration | Known-CVE escape | Novel exploit |
|---|---|---|---|---|---|
| Nothing (plain host) | no | no | no | no | no |
| Separate OS user | yes | partial | no | no | no |
| Process sandbox + kernel-enforced egress | yes | mostly | partial | no | no |
| Container + kernel-enforced egress + brokered credentials | yes | mostly | partial | no | no |
| gVisor | yes | yes | partial | largely | partial |
| MicroVM | yes | yes | partial | yes | partial |
| Full VM, no host share | yes | yes | partial | yes | yes |
| WASM runtime | yes | yes | yes | yes | yes, within its API |
Two columns deserve a warning. Adaptive exfiltration stays "partial" everywhere because a sandbox cannot stop an agent from doing something permitted that you did not want — posting a summary to an allowed host, opening a pull request, spending tokens. That is what the human gate is for. Novel exploit stays "partial" even for VMs because a hypervisor is code, and code has bugs.
The escape benchmark
The most useful published measurement in this space is SandboxEscapeBench (ICML 2026). A ReAct agent with a shell in a container is asked to read a file outside the container. Its findings are worth reading carefully because they are more encouraging than the headline suggests.
The scenarios that always fall
Difficulty 1–2 were reliably exploited, and they are not exotic: an exposed Docker socket, a writable
host bind mount, and a --privileged container. Those three appear in the quickstart templates
of essentially every agent framework. The benchmark's own conclusion is that the real deployment
landscape lives at difficulty 1–3, which is exactly the band where models succeed.
The scenarios that never fall
Nothing at difficulty 4–5 succeeded. Models did not invent a memory-corruption exploit for a hardened microVM. That is why the honest framing is: hardening moving you out of the "known CVE and misconfiguration" zone is a real and large win, and it is achievable today.
A behavioural detail worth knowing
The models behaved differently under pressure. One disengaged in 92.3% of its failures; another hallucinated success in 86.7% of failed attempts, claiming it had escaped when it had not; Claude models were described as essentially refusal-free and attempted until the token limit. If you are reading an agent's own report of what it did, you are reading an unreliable narrator.
A review of 39 papers on agent isolation found policy failure rates of 69–98% against real denylists, with out-of-scope action rates up to 17.1% under realistic prompting. The same body of work identifies the field-wide blindspot as conflating "we run in Docker" with "we are isolated".
One multi-substrate study concludes: "agents are not breaking out of containers; they are being tricked into reading the wrong file in the same data directory." That is a much more useful threat model than the escape fantasy, because it is what actually happens — and it is addressable with path discipline rather than with hypervisors.
The CVE record, honestly read
Over a 24-month window the independent study counted eleven engine-level CVEs across five products, and roughly 3,500 in the Linux kernel that all of the container-based ones share. That ratio is the whole argument about shared kernels in one number.
| Engine | Class | Engine CVEs | Escape-class | What it tells you |
|---|---|---|---|---|
| Firecracker | microVM | 2 | 2 | The "no published hypervisor escape" baseline broke twice in four months: an out-of-bounds write in virtio-pci and a jailer symlink host-write. Disclosure works; that is why you can see them. |
| Cloud Hypervisor | microVM | 2 | 1 | First published escape-class advisory: a virtio-block async-I/O use-after-free at 8.9. Patched, with an advisory, the same day. |
| libkrun | microVM | 0 | 0 | Zero CVEs, no upstream fuzzer, no published study. The study calls this "exposure undefined" rather than safe, and ranks its residual-bug risk highest. |
| gVisor | App kernel | 3 | 0 | Two information leaks and one internal escape, no escape-class issues in the window, and the only continuous public fuzzing dashboard of the group. |
| runc | Container | 4 | 4 | All four escape-class, including three that recur the same procfs mount-race pattern. This is the shared-kernel tax, and it is paid by every container on the machine. |
| Linux kernel | Shared by all containers | ~3,500 | — | Two and a half orders of magnitude more than all five engines combined. Not a reason to panic; a reason to stop calling a container isolated. |
Microsoft's security servicing criteria exist to define what it will patch as a security bug, and they do not treat process-isolated containers — which share the host kernel — as a security boundary, nor do they recommend them for hostile multi-tenant scenarios. Hypervisor-isolated containers are treated differently. Docker's own enterprise material concedes that on WSL a user can enter the Docker Desktop distribution as root and that all distributions share one kernel, so kernel integrity cannot be guaranteed. When the platform vendors describe their own isolation this carefully, a wrapper's README should not be more confident than they are.
Documented bypasses, in one place
Every row below is a real advisory, incident or vendor disclosure. They are not a reason to avoid the tools — they are the reason to know how each kind of boundary fails.
| Class | Example | Root cause | Lesson |
|---|---|---|---|
| Exposed control surface | The Docker socket escape performed autonomously by an LLM harness | A socket that is root-equivalent was mounted into the agent's environment | Every capability you mount is a capability the agent will use |
| Path identity | Symlink sandbox escape (CVE-2026-39861) | Path validated before use, target swapped between check and open | Path-based rules are fragile; inode labels survive renames |
| A local socket | D-Bus escape via systemd-run --user (CVE-2026-47128) | Landlock policy permitted Unix domain sockets without path mediation | Any local socket you allow is a control channel |
| A file that did not exist | Config-mutation at startup (CVE-2026-25725) | Bind mounts cannot hide paths that do not exist yet | Know your primitive's asymmetry — macOS globs, bind mounts do not |
| A reasoning adversary | Agent found /proc/self/root/usr/bin/npx, then disabled its own sandbox | Denylist plus an approval model the agent can argue with | Allowlists, and make the sandbox non-negotiable |
| A host bridge | WSL2 interop deleting 26.8 GB with no approval | Interop spawns native Windows processes outside every namespace | Bridges are outside the sandbox; audit them separately |
| A parsing bug | Browser agent allowlist bypass (CVE-2025-47241) | URL userinfo syntax defeated the only native domain restriction | Allowlists die at the parser |
| Arguments on a command line | Secrets readable via /proc (CVE-2026-61670) | Credentials passed as command-line arguments are world-readable on many systems | Never pass a secret as an argument or an environment variable |
| A trust handoff | The allowlisted package-proxy escape | The agent used an approved service to reach somewhere unapproved | An allowlist constrains destinations, not intentions |
| Fail-open | Sandbox continued unsandboxed when Landlock was unavailable | A graceful degradation path that gave up enforcement | Refuse to run; test the degradation path on purpose |
| A host helper | Credential helpers resolved by name through PATH | The sandbox could write to a directory on the search path | Pin helper paths; sanitise PATH |
| An unguarded approval path | A hidden hardware-companion protocol that auto-approved every tool call | An approval channel nobody was auditing | Audit the control plane, not only the sandbox |
How to read a security claim
Most of the marketing in this space is technically true and practically misleading. These are the phrases that should make you slow down, and the question to ask instead.
| The claim | Ask instead |
|---|---|
| "Secure sandbox" | Secure against which of the three tiers? A boundary claim without a threat model is a mood. |
| "Kernel-level isolation" | Whose kernel? If it is the host's, it is a namespace. |
| "Zero CVEs" | Who is looking? Absence of advisories is an absence of search until proven otherwise. |
| "Hardware-isolated" | Does the product actually pin the VMM version, and how quickly does it take upstream fixes? The study's worst findings were pin-policy findings, not engine findings. |
| "Network allowlist" | Kernel-enforced or environment variables? Does it fail closed? Is DNS filtered? Is the metadata endpoint blocked? |
| "Credentials never leave your machine" | Where does the proxy run, and what stops the agent reading it? |
| "Runs in WSL2" | Is interop disabled, and is /mnt mounted? |
| "Deny-by-default" | What happens when the configuration is empty, and what happens when a component is missing? |
| "Open source and audited" | Audited by whom, published where, covering which commit? And is the current code still the code that was audited? |
- Can the agent's code reach the host kernel? If yes, you are relying on the kernel's CVE response, not on your sandbox.
- What does the agent hold that is worth stealing? If the answer is "nothing, because it has placeholders", you have removed the highest-probability incident class.
- What can the agent do that is irreversible, and who approves it? If the answer is "anything it can reach, and nobody", no amount of isolation fixes the problem — because the damage happens inside the sandbox, legitimately.
Layers that fail independently, secrets that are not present, egress that is in the kernel, work that arrives as a diff, and a human who reads the diff for anything consequential. Every one of those is boring, and together they are worth more than any single product in this guide.