Docker AI Ecosystem 02: Why AI Agents Need MicroVM Sandboxes

Sysadmins have said for a decade that a container is not a security boundary. Hand one an autonomous agent that runs shell commands as you, and that old warning suddenly has teeth. This part makes the case for giving an agent its own kernel, and explains the architecture behind Docker Sandboxes.

There is an old line among people who run infrastructure: a container is not a security boundary. We have repeated it for a decade, usually to someone about to run something sketchy as root with the Docker socket mounted. With autonomous agents, that warning finally grew teeth, because now the sketchy thing decides for itself what to run, as you, at full speed. This part makes the case for giving an agent its own kernel.

This is Part 02 of the Docker AI Ecosystem series. Part 01 ran models locally; from here we run the agents that drive them.

1. The New Threat Model #

A web application is, security-wise, fairly predictable. It does what you wrote it to do. An agent is not like that. You hand it a goal and it decides, at runtime, which shell commands to run, which files to edit, which tools to call, and what to fetch over the network. The whole selling point is that it acts without stopping to ask.

That is also the whole problem. As one Docker writeup put it, an AI coding agent is "a junior developer with root access, the ability to type at 10,000 words per minute, and no instinct for when to stop and ask." The capability is real and so is the missing judgment. Run that on your machine and it runs as you, with your permissions, your credentials, your filesystem. What could go wrong, goes wrong.

And it is not hypothetical. The agents in question are the ones sitting on your machine right now, Claude Code, Gemini CLI, GitHub Copilot CLI, Codex, OpenHands. There are well-documented cases of one running rm -rf into a home directory because a path expansion was technically "in scope," of one wiping a production database during an explicit code freeze after being told eleven times not to, of malware that detected an installed agent and used its auto-approve mode to go hunting for credentials, and even of an agent quietly spinning up a cryptominer and a reverse SSH tunnel that its assigned task never mentioned. Destruction and data theft are the obvious threats; resource hijacking is the quiet one, a prompt-injected agent that mines crypto or melts your CPU costs you money without ever deleting a file. We cover the developer's side of this mess in Part 03.

2. Why a Container Isn't Enough #

The instinct of anyone who runs servers is: fine, put it in a container. That instinct is right that you need isolation and wrong that a container is enough of it. Two reasons.

A container shares the host kernel. This is the defining feature of containers and normally a good one, it is why they are so cheap. But it means a container is not a hard wall. A kernel-level exploit triggered inside the container is an exploit of the host kernel, because there is only the one. You can see the shared kernel in a single line:

echo "host:      $(uname -r)"
echo "container: $(docker run --rm alpine uname -r)"
host:      6.17.0-29-generic
container: 6.17.0-29-generic

Identical, because it is literally the same kernel. A container escape does not hand an attacker the container. It hands them the host.

Agents need Docker, and giving them Docker breaks the box. Coding agents build and run containers as part of normal work, clone a repo, build an image, bring up a compose stack, run the tests. To do that from inside a container you reach for Docker-in-Docker, which in practice means mounting the host's Docker socket. And the Docker socket is root on the host. A container with the socket mounted can see and control every container on the machine:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock docker:cli \
sh -c 'docker ps --format "{{.Image}}"'
docker:cli
docker/model-runner:latest
postgres:15-alpine
... (every container on the HOST)

From there it is a short hop to launching a privileged container that mounts the host's entire filesystem. So the very capability the agent needs is the one that dissolves the isolation you built. You end up choosing between an agent that cannot do its job and an agent that can do anything. That is not a fun menu.

3. What a MicroVM Actually Is #

The way out is to give the agent its own kernel. A full virtual machine does that, but traditional VMs are heavy and slow to boot, built for long-running servers, not for spinning up a throwaway box per task.

A microVM is the compromise that actually works: real hardware virtualization, a separate guest kernel, but stripped to the bone for fast startup and low overhead. It skips the legacy device emulation, the BIOS/UEFI dance, and the general-purpose baggage of a full VM, and keeps only what a short-lived, single-purpose workload needs. The result is VM-grade isolation that boots in seconds and packs densely, instead of the minutes and gigabytes of a classic VM. It is the same idea that quietly powers serverless platforms under the hood; pointed at agents, it means each session gets a genuine hardware boundary while still feeling as disposable as a container.

4. How Docker Applies This to Agents #

Docker Sandboxes is Docker's productized version of this, and the design answers the problems in Section 2 head-on:

  • A dedicated kernel per session. A hardware boundary from the host and from other sandboxes. A compromise inside one does not reach out.
  • A private Docker daemon inside the microVM. This is the clever bit. The agent gets a full, real Docker daemon, so docker build, docker run, and docker compose all work natively, but it is the sandbox's daemon, not your host's. No socket mounting, no host privileges. The agent gets to act like a developer without getting the keys to your machine. It is also a quality-of-life win: the agent can spin up its own messy docker compose stacks and leave dangling images and stopped containers strewn everywhere, and when the sandbox is torn down so is all of it. Your host's Docker stays pristine.
  • Boundaries set before the agent runs, not by it. Filesystem scope, network policy, and secrets are defined up front and injected at runtime. The governing principle, in Docker's words: "An LLM deciding its own security boundaries is not a security model." Quote that one to anyone who suggests just prompting the agent to behave.

The official architecture describes layered isolation, the VM boundary, the network, the in-VM Docker engine, and a credential proxy that injects secrets without the agent ever seeing their values. We turn those into knobs you can set in Part 03.

And this is not just documentation, I ran it. sbx is not a cloud service: with docker-sbx installed it boots the microVMs locally on KVM. sbx create shell . gives you a sandbox, and the two headline claims above hold up. First, the dedicated kernel, the sandbox reports a different kernel than the host:

uname -r                       # host
sbx exec mybox uname -r # inside the sandbox
6.17.0-29-generic              # host
7.0.8                          # sandbox: its own guest kernel

That different kernel string is the hardware boundary, this is not a shared host kernel like a container. Second, the private in-VM Docker daemon: docker ps inside the sandbox sees only its own engine, empty, while my host was running a dozen containers:

sbx exec mybox docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

And reaching for the host filesystem simply fails, sbx exec mybox ls /home/test returns No such file or directory. The agent is genuinely boxed in.

One gotcha that cost me an afternoon: sbx reads its credentials from the desktop keyring, so over a bare SSH session with a locked keyring it hangs on startup with no error (it is blocked on a keyring unlock prompt nobody can answer). Unlock the keyring, or run it from a graphical session, and it springs to life.

5. Container vs MicroVM vs VM #

Side by side, drawing on Docker's own comparisons:

Container MicroVM Full VM
Isolation boundary Shared host kernel Own guest kernel Own guest kernel
Safe for untrusted agents Weak (escape = host) Strong (hardware) Strong (hardware)
Boot time Milliseconds Seconds Minutes
Resource overhead Low Modest High
Native Docker for the agent Only via socket (unsafe) Yes, private daemon Yes
Built for App workloads Ephemeral sessions Long-running servers

One detail I appreciated: Docker built its own VM monitor rather than adopting Firecracker, the microVM monitor behind AWS Lambda, so the same sandbox behaves the same way everywhere without a tower of fragile shims. The reasoning is refreshingly practical: if the sandbox is slow or fiddly to set up, developers turn it off, and a sandbox nobody runs protects nobody. That is the most honest design constraint in the whole stack.

6. When You Actually Need It #

Not every workload needs a microVM, and saying so is what keeps the advice trustworthy.

  • You do not need it for trusted, deterministic jobs, your own CI lint step, a build you wrote, a service you control. A container is the right tool and the shared kernel is a feature, not a flaw.
  • You do want it for an autonomous agent that has network access, filesystem access, and the freedom to run arbitrary commands, especially one chewing on untrusted input (a web page, an email, a third-party package) where a hidden instruction can turn the agent against you.

The deciding question is blast radius. If the worst plausible outcome of this process going rogue is "it trashes its own scratch directory," a container is fine. If the worst plausible outcome is "it deletes my home directory or mails out my cloud credentials," you want a boundary the process cannot reason its way around. Isolation is cheap insurance against an agent that "helpfully" runs the wrong command at 3 a.m.

Summary #

  • A container shares the host kernel, so an escape is a host compromise, it is isolation, not a security boundary.
  • Agents need Docker, and the usual way to give it to them (the socket) hands over the whole host.
  • A microVM gives the agent its own kernel with near-container speed, closing both gaps.
  • Docker Sandboxes adds a private in-VM Docker daemon and up-front, infrastructure-set boundaries.
  • Use a container for trusted work; reach for a microVM when the blast radius is your real machine.

Next #

Part 03 takes this off the whiteboard and onto the keyboard: how to run an agent in "YOLO mode" without putting your real machine at risk, including a hardened throwaway sandbox you can build today with plain Docker flags, and a fully local agent that never phones home.


← Previous · 01: Local LLMs with Model Runner Next · 03: Running Agents Safely →