Sandboxing an AI agent means running it where the damage it can do is bounded: no access to the host, to the network, or to data the task doesn’t need. On Linux the choices are containers, microVMs and user-space kernels such as gVisor, and the right one depends on how much you trust code that, by definition, nobody has reviewed before it runs.
This guide covers why agents need stronger isolation than ordinary workloads, how the three options compare, why two runs of the same image don’t behave the same, and a practical starting setup with Incus. It describes general, public practice only.
Why does an AI agent need a sandbox?
An agent is a program that writes and runs other programs. A coding agent installs packages, runs build scripts and executes tests. An operations agent runs shell commands against live systems. Whatever the agent decides to run, your machine runs.
That makes the agent’s environment an attack surface in two directions. Inward, a prompt injection in a web page or a dependency README can steer the agent into running something hostile. Outward, the agent itself may try to reach beyond its box, whether by instruction, by accident or because it has learned that doing so gets a task marked done. Sandbox escape is the name for the second case, and it is now measured directly: Quantifying Frontier LLM Capabilities for Container Sandbox Escape benchmarks how capable frontier models are at breaking out of container sandboxes (Sandbox escape benchmark, 2026).
The conclusion is not that agents are malicious. It is that an agent’s isolation has to be designed for an adversary, because you cannot predict what it will run.
Containers, microVMs or gVisor?
Three isolation models are in common use, and they trade security boundary against cost.
| Containers | gVisor | MicroVMs | |
|---|---|---|---|
| What isolates | Kernel namespaces and resource limits on a shared host kernel | A user-space kernel that mediates the container’s system calls | A separate guest kernel on a hardware-virtualised machine |
| Boundary | The host kernel’s attack surface | The user-space kernel; the host kernel sees far fewer calls | The hypervisor |
| Overhead | Lowest | Moderate; some system calls are slower | Low at runtime; more memory per instance |
| Startup | Milliseconds | Milliseconds | Hundreds of milliseconds to seconds |
| Fits | Trusted code, dense packing | Untrusted code that still needs container tooling | Untrusted code, strongest boundary, GPU and device passthrough |
| Examples | Docker, Podman, LXC, Incus system containers | gVisor (runsc) | Firecracker, Cloud Hypervisor, Incus virtual machines |
Containers share the host kernel. They are fast and cheap, and every kernel vulnerability is a potential escape. Standard hardening applies: unprivileged containers, dropped capabilities, read-only root filesystems, system-call filtering with seccomp, and no privileged devices. For an agent, treat a plain container as the floor, not the ceiling.
gVisor puts a user-space kernel between the workload and the host. The container’s system calls are served by that layer, so the host kernel is exposed to a much smaller set of operations. The cost is compatibility and performance for system-call-heavy work, which agent tasks often are.
MicroVMs give each workload its own kernel on a small virtual machine. The boundary is the hypervisor, which is the strongest of the three, and the price is memory per instance and slower starts. For long-running agents or anything with GPU access, the price is usually worth paying.
A reasonable default for an agent lab is a microVM or system container per task, created fresh and destroyed after. Reuse is where sandboxes rot.
Why isn’t “same image, same behaviour” true?
Teams often assume that an agent run is reproducible if the container image is pinned. It isn’t, for three reasons.
Model inference is not deterministic, even at temperature 0. Floating-point arithmetic on GPUs doesn’t guarantee the same result for the same input across batch sizes or hardware. Understanding and Mitigating Numerical Sources of Nondeterminism in LLM Inference traces output variance to numerical precision and finds that lower-precision formats such as BF16 diverge where FP32 holds steady (Numerical nondeterminism, 2025). Thinking Machines reaches the same conclusion from the serving side and attributes the variance to compute routines whose results depend on batch composition (Thinking Machines, 2025).
Timing differs. Network latency, scheduler order, and the wall-clock time an agent reads all vary between runs. A command that times out in one run succeeds in the next.
The agent’s path compounds the differences. A one-token difference early in a run changes the next command, which changes the output the agent reads, which changes everything after. Two runs of the same agent on the same image and the same task can end in different places.
The practical consequence is that you cannot replay an agent run to find out what happened in it. The record has to be made during the run, by something that isn’t the agent, and kept where the agent can’t change it. Qin et al. found that most agent harnesses they tested let the agent delete its own trace, and recommend logging outside the agent’s control (Qin et al., 2026).
What does a practical Incus setup look like?
Incus manages both system containers and virtual machines with one tool and one image store, which makes it a good fit for a small agent lab. A starting setup, using only standard features:
- One instance per task. Create it from a snapshot of a prepared base image, run the task, export the results, destroy the instance. Never let a second task inherit a first task’s state.
- Unprivileged containers or VMs. Unprivileged containers map root inside to an unprivileged user outside. Where the task will run untrusted code with any real capability, use a VM.
- No outside network by default. Put instances on an isolated bridge with no route out. Add a filtered egress only for tasks that need a named service, such as a package mirror you host.
- Resource limits. Cap CPU, memory, disk and process count per instance, so a runaway agent degrades its own box and not the host.
- Snapshots before and after. A snapshot at the start fixes the initial state; a snapshot at the end fixes the final state. The difference is your outcome evidence, taken from the host side rather than from the agent’s report.
- Results leave the instance; nothing comes back. Copy artefacts out to host storage the instance cannot mount. Keep whatever logs the host or hypervisor produces outside the instance as well.
- Fresh base images on a schedule. Rebuild the base from a declarative definition so that the environment is documented, not accumulated.
None of this is exotic, and none of it is sufficient on its own. It gives you bounded damage, a clean start per task, and a final state you observed rather than were told about. Inoku’s private evaluations run agents in isolated environments of this kind, so the agent is tested as shipped, with no code changes. Evidence Every factual claim on this page links to one of these. Numbers in brackets refer to this list.Sources