Why AI agents that run code need a sandbox
An AI agent sandbox is an execution environment that limits what code run by an agent can reach: files, network, credentials, other processes and the host kernel. Agents run code more often than teams expect. Coding agents run tests and install packages. Data agents write and execute Python. Tool servers shell out to the system. That makes a sandbox for code-executing agents a baseline control, not an extra.
OWASP lists this risk as ASI05 Unexpected Code Execution in its Top 10 for Agentic Applications, published in December 2025. It notes that agentic systems "often generate and execute code," and that prompt injection and unsafe serialization can turn text into executable behavior. Its mitigations include "Never run as root" and running code in "sandboxed containers with strict limits including network access."
Once attacker code runs, it inherits the agent's reach: the network, credentials on disk, the host's files, other tasks and the machine itself. A poisoned document, a malicious dependency or a tool that obeys a file is enough to get there. The useful question is not whether hostile code will ever run, but what it can touch when it does. For how ASI05 relates to the other nine risks, see the OWASP agentic Top 10 guide, and for the wider program, the AI agent security guide.
Design for assume-breach
Assume-breach design starts from one premise: the code inside the sandbox already belongs to the attacker. Every boundary is designed for that case, not for the cooperative one. The goal is to contain a compromised AI agent, not to prevent every compromise.
Four questions define the boundary:
- What can it reach? Files, network, other processes, and the kernel's system-call surface.
- What can it take? Credentials, tokens, workspace data, and data from other tasks.
- How much can it consume? Memory, processes, CPU, disk and time.
- What evidence survives? Logs the code inside cannot edit or delete.
The answers that follow are strict. No network by default. No credentials inside. A read-only root filesystem and one writable workspace. An unprivileged user with no capabilities. Hard limits on resources and time. One narrow exit, outside the sandbox's control, that applies policy to everything leaving.
Success has a clear test: code execution happens inside the sandbox, and its effect stays there. A sandbox that only holds when the code behaves is not doing its job.
AI agent isolation options compared
| Option | Boundary | Start-up cost | Strength | Does not cover |
|---|---|---|---|---|
| Containers (standard runtime) | Namespaces and cgroups on a shared host kernel | Low: a process plus image setup | Good against accidents and casual misuse | Kernel exploits; egress and secrets unless you configure them |
| gVisor | A user-space application kernel between code and host kernel | Low fixed cost; extra cost per system call | Much smaller host-kernel surface | Some system calls and /proc files; slow for syscall-heavy work |
| MicroVMs such as Firecracker | Hardware virtualization with a separate guest kernel | Boot under 125 ms, under 5 MiB memory overhead (Firecracker's figures) | Strongest common boundary | Needs KVM on the host; network and credentials are still yours to design |
| Kernel primitives used directly | Namespaces, seccomp, Landlock and cgroups on a shared kernel | Lowest: a process start | Strong when combined tightly | Kernel exploits; you own the composition and its tests |
| Hosted code-interpreter sandboxes | The provider's environment | A network round trip | Depends on the provider | Your data leaves your environment; your egress and identity rules may not apply |
| Open-source agent sandboxes, such as NVIDIA OpenShell | Kernel controls plus declarative policy | Varies by project | Packaged defaults for agents | Project maturity; whether the calls it allows are safe |
Reading the table
gVisor describes itself as "an application kernel that implements a Linux-like interface," written in Go and running in user space. The price, in its words, is "reduced application compatibility and higher per-system call overhead" (gVisor). Firecracker runs microVMs on the Linux Kernel-based Virtual Machine (KVM) and adds a "jailer" as "a second line of defense in case the virtualization barrier is ever compromised" (Firecracker).
Kernel primitives need care in combination. The kernel's own documentation says "System call filtering isn't a sandbox"; seccomp minimizes the exposed kernel surface and is one tool among several (seccomp). Landlock, available since Linux 5.13, lets an unprivileged process restrict its own file and network access (Landlock).
NVIDIA describes OpenShell as "an open-source runtime for executing fleets of autonomous AI agents in sandboxed environments with kernel-level isolation," using Landlock, seccomp and network policies. As of October 2026 its documentation lists 0.1.x releases (NVIDIA OpenShell).
A workable rule of thumb: for your own agents reading untrusted documents, layered kernel primitives or gVisor, with no network and no credentials. For code from customers, or many tenants on shared hosts, a microVM. For hosted interpreters, only data you would be comfortable sending to that provider anyway.
Network egress and credentials
No network by default
Give the sandbox an empty network namespace. Network namespaces isolate network devices, protocol stacks, routing tables and firewall rules, and also the abstract Unix socket namespace (network_namespaces(7)). With no usable interface, there is nothing to connect to.
When a task needs the network, do not open a route. Give it a broker: one socket into the sandbox, connected to a process outside that makes requests on its behalf. The broker allows named destinations and methods, inspects payloads with your data protection rules, and holds anything leaving the company for review.
Close the quiet channels too. DNS lookups can carry data out, and cloud metadata endpoints can hand out credentials, so neither should be reachable. If you must allow direct egress, Landlock (ABI 4 and later) can restrict TCP connections to listed ports, as a second layer behind a filtering proxy.
Keep credentials outside the sandbox
Anything inside the sandbox belongs to the attacker, including credentials. So put none there: no API keys in environment variables, no mounted cloud config directories, no service account tokens, no SSH agent socket.
The broker adds credentials on the way out. The code asks to send an email; the broker checks the request, attaches a short-lived, narrowly scoped credential, and makes the call. Hostile code can ask, but it cannot take the key and use it elsewhere. If a task truly needs a credential inside, such as a token to clone one private repository, scope it to that task and let it expire within minutes. OpenShell takes a similar approach, resolving "opaque credential placeholders only at profile-authorized endpoints." Combined with per-call authorization, the broker decides not only whether a request may leave, but whether this agent may make it at all.
Resource limits and sandbox lifetime
Resource limits
Hostile code does not need to escape to cause harm; it can exhaust the host. Use cgroup v2 controls (cgroup v2):
pids.maxcaps processes. Forks beyond the cap fail withEAGAIN, which stops fork bombs.memory.maxis a hard memory limit. At the limit, the out-of-memory (OOM) killer runs inside that cgroup only.cpu.maxcaps CPU time, so one task cannot starve the others.
Add a wall-clock timeout per task, a size cap on the writable workspace, and a limit on how much output returns to the agent. Treat a limit being hit as a signal, not just a stop: a task that reaches its process cap or memory limit deserves a look, and repeated hits from one agent may mean it is being steered.
Per-task vs per-session sandboxes
A per-task sandbox is created for one task and destroyed when it ends. Nothing persists, so a compromise cannot carry into the next task, and a planted file cannot wait for a later reader. The cost is start-up time on every task and no warm caches.
A per-session sandbox lives for one user's session, such as a coding session. It is faster to work in and keeps installed packages. OWASP recommends isolating "per-session environments with permission boundaries." The risk is that anything planted early in a session runs later in it.
Use per-task sandboxes for untrusted input: outside documents, web content, customer files. Per-session is reasonable for one user's interactive work if the sandbox is destroyed at session end. Never share a sandbox across users or tenants. Persist results through the broker, where they can be inspected, rather than by keeping a sandbox alive.
What isolation does not solve
A sandbox contains code. It does not judge the actions an agent is allowed to take through the broker. An agent talked into a $4,500 refund through an approved billing call has escaped nothing; every boundary held. That needs per-call authorization, spending limits and human approval.
Isolation also does not:
- Stop prompt injection. It limits what injected code can do, not what the model decides.
- Protect data sent on purpose. Prompts to model providers and allowed messages need data protection.
- Fix shared-kernel bugs. Containers and kernel-primitive sandboxes depend on a patched, hardened host kernel; gVisor and microVMs reduce that exposure.
- Reach agents that never run on your hosts. Agents on SaaS platforms need discovery, and the tools they call need MCP security.
Testing your sandbox: an attack test plan
Test the sandbox the way an attacker would use it. Run these steps as code inside a fresh sandbox, in continuous integration (CI), after every image change and kernel update. The core steps follow the attack in AgentFort's Isolation demo, recorded against Northwind, a simulated company; the others close common gaps.
| Step | What the test code does | Expected result |
|---|---|---|
| 1 | Opens a TCP connection and makes a DNS lookup | Fails: no route, no resolver |
| 2 | Searches environment variables and disk for keys and tokens | Nothing found |
| 3 | Requests the cloud metadata endpoint | Unreachable |
| 4 | Reads host home directories or other tasks' files | Denied |
| 5 | Writes to the root filesystem | Read-only error |
| 6 | Mounts a host filesystem | Refused by the kernel |
| 7 | Loads a BPF program and a kernel module | Refused |
| 8 | Creates a new user namespace | Refused |
| 9 | Forks without limit | Stopped at the process cap |
| 10 | Allocates memory past the limit | Killed inside its own cgroup |
| 11 | Sends a customer list to an outside address via the broker | Held for review |
| 12 | Sends a message containing a secret via the broker | Blocked |
| 13 | Checks the records for steps 1 to 12, from outside | Each attempt logged with destination and reason |
A pass is not "the code failed". A pass is "the code failed for the reason you designed", so assert the specific error. Include the person the agent acts for in step 11: they should be able to see the held message but not approve it.
AI agent sandbox checklist
- Run every task that executes agent-written or third-party code in a sandbox, never directly on the host.
- Run as an unprivileged user with no capabilities, never as root.
- Mount the root filesystem read-only and give each task one writable workspace.
- Start with no network, and route needed calls through a broker with an allow-list.
- Keep every credential outside the sandbox, and let the broker attach it per request.
- Filter system calls with seccomp and confine file access with Landlock or an equivalent.
- Cap processes, memory, CPU, disk and wall-clock time.
- Create a fresh sandbox per task for untrusted input, and destroy it afterward.
- Keep logs where the code inside cannot reach them.
- Rerun the attack test plan after every image or kernel change.
How AgentFort handles this
AgentFort Isolation assumes the code inside the sandbox is already the attacker's and contains the blast radius. Each task runs in its own sandbox built from Linux kernel features, with no virtual machine. It has no network: an empty network namespace. Its root is read-only, a Landlock ruleset keeps it to its workspace, and it runs as an unprivileged user with no capabilities. A seccomp filter refuses mounting, kernel modules, BPF and new user namespaces, and a cgroup caps memory and processes. The only way out is one socket to a broker, which inspects everything with AgentFort Data Protection, adds credentials the sandbox never sees, and holds anything leaving the company for a person. In the Northwind demo, the cgroup stopped a fork bomb at 127 processes. See AgentFort Isolation.
Frequently asked questions
Is a Docker container a secure sandbox for AI agents?
A standard container is a useful start, not a complete sandbox. Containers share the host kernel, so a kernel exploit can cross the boundary, and common defaults allow outbound network access and often pass credentials in environment variables. Harden it with no network, a read-only root, an unprivileged user, a tight seccomp profile and resource limits. For code you consider hostile, add gVisor or a microVM.
Do I need a microVM to run AI-generated code?
Not always. A microVM gives the strongest common boundary because the code gets its own guest kernel, which matters when code comes from untrusted users or many tenants share hosts. For one organization's agents, gVisor or a hardened kernel-primitive sandbox with no network and no credentials may be enough. Decide by who writes the code and what else shares the host.
How do I contain a compromised AI agent?
Act in this order. Stop the agent's tasks and destroy its sandboxes. Suspend its identity and revoke any credential it could have reached. Block its outbound paths at the broker or gateway. Then review its records to see which calls succeeded, what data left and which systems need cleanup. Containment is far easier when the agent never held long-lived credentials.
Do coding agents on developer laptops need a sandbox?
Yes. A coding agent runs commands with the developer's rights: source code, SSH keys, cloud credentials and the corporate network. A poisoned README or dependency can turn that into an attacker's foothold. Run the agent's commands in a container or operating-system sandbox scoped to the project folder, with network access limited to package registries and the services the task needs.
Can I run untrusted MCP servers in a sandbox?
Yes, and for local servers you should. Run each server as its own unprivileged user in a container or operating-system sandbox, mount only the directories its tools need, and give it no network unless a tool needs specific hosts. Supply credentials through a broker or short-lived tokens rather than config files, and pin the server version you reviewed.