AI Agent Sandboxes: Why a Single Container Isn't Enough


An AI agent that knows how to write code will inevitably start executing it. At first, it’s a harmless python -c, followed by npm install, docker build, and eventually terraform apply. These commands are generated by a model and run directly on your infrastructure, where secrets, internal services, and sensitive data might reside.
That makes it critical to consider not just what code the agent generates, but where that code executes and what it can reach.
Containers work well for many workloads, but they share the host system’s kernel. When arbitrary code runs inside a container—especially code crafted to bypass restrictions—container-level isolation may fall short. A stronger alternative is a dedicated virtual machine with its own Linux kernel that you can discard once the task finishes.
In microsrv, you can spin up such a sandbox in 5–10 seconds. In scale-to-zero mode with state persistence, the virtual machine goes to sleep during idle periods and wakes in 100–250 ms.
In short: containers are great for running trusted services and routine workloads. For arbitrary AI agent code that cannot be trusted with host access, a virtual machine provides a much stronger isolation boundary. To avoid paying for idle resources, the sandbox can sleep between model steps and be deleted once the task is complete.
1. What Happens When an AI Agent Gets Terminal Access
The distinction between an agent that merely suggests fixes and one that autonomously modifies a system often comes down to a single tool: shell.
With terminal access, an agent can install dependencies, build projects, run test suites, query remote APIs, and modify local files. While this is powerful, it introduces several distinct security risks.
Errors and unintended consequences. A model can misinterpret instructions, pick the wrong command, or overlook side effects. Instead of rm -rf ./build, it might execute a destructive command against an unintended path. This requires no malice—an ordinary mistake is enough.
Instructions from untrusted sources. Agents ingest tickets from issue trackers, download documentation, clone repositories, and crawl websites. Any of these inputs can contain prompt injection attacks designed to hijack the model’s behavior. If the agent holds credentials and network access, it might be coerced into exfiltrating data to an attacker-controlled server.
Demands for elevated privileges. Building a project often requires system packages, native toolchains, background daemons, filesystem mounts, or Docker. Unprivileged user restrictions can get in the way, creating a temptation to grant root privileges or expose low-level system interfaces.
Access to internal networks. Even if an agent runs without administrative privileges, its environment might have network access to databases, internal APIs, message brokers, or cloud instance metadata. A compromised agent can quickly become a pivot point across your private network.
The answer is not trying to anticipate every dangerous command, but containing the blast radius. The code must execute in an isolated environment without unneeded privileges, host access, persistent secrets, or internal network reachability. Once the task finishes, the entire environment should be discarded.
2. What a Sandbox Must Defend Against
Standard Linux containers rely on namespaces, control groups (cgroups), and security profiles such as seccomp to isolate processes, allocate resources, and restrict capabilities.
However, containers sharing a host also share that host’s Linux kernel. System calls originating from containerized processes are ultimately serviced by the host kernel. If a vulnerability allows an attacker to escape those bounds, the blast radius extends to the host itself.
Here are four scenarios to consider when designing a sandbox architecture.
Linux Kernel Vulnerabilities
In 2022, the Dirty Pipe (CVE-2022-0847) vulnerability was disclosed. Under specific conditions, it allowed unprivileged processes to overwrite read-only files in the page cache.
This demonstrates why timely kernel patching is vital. When multiple containers share a single vulnerable kernel, every container shares the risk. Containerization alone cannot protect against kernel bugs.
Container Runtime Vulnerabilities
Security flaws can also arise in the runtime components that manage containers. For example, CVE-2019-5736 affected runc, the container runtime. Under certain conditions, an attacker could overwrite the host runc binary from within a container, achieving root code execution on the host.
This highlights that isolation guarantees depend on the entire stack, not just container namespace boundaries.
Excessive Privileges
A sandbox escape doesn’t always require an unpatched vulnerability; misconfiguration is often enough.
Running containers with --privileged, mounting /var/run/docker.sock, or granting sensitive capabilities like CAP_SYS_ADMIN severely weakens isolation. Depending on the setup, an unprivileged process inside the container can take control of the host or manage peer containers.
Granting such permissions to an AI agent simply to allow Docker builds is dangerous. Image builds should run in an isolated environment designed specifically for that purpose.
Access to Internal Networks and Secrets
Data exfiltration doesn’t require a container escape. If an agent can reach internal VPC services, inspect environment variables, or read cloud metadata endpoints, it can leak sensitive information without touching the kernel.
For instance, an injection payload in a parsed document could instruct the agent to send an API token to an external endpoint. Process-level isolation cannot prevent this if network access and credentials are broad by default.
Mitigating this requires independent network controls: restrictive egress rules, minimal short-lived credentials, and clear separation between agent orchestration and arbitrary code execution.
Takeaway: containers remain an indispensable tool for trusted services. But when executing arbitrary, untrusted code, you must evaluate the shared-kernel attack surface, privilege escalation risks, network exposure, and data leakage vectors.
3. Containers, gVisor, and KVM: How They Compare
Each approach provides different isolation boundaries and comes with different trade-offs.
| Criterion | Docker / containerd | gVisor | KVM |
|---|---|---|---|
| Kernel | Shared host kernel | Sentry userspace kernel | Dedicated guest OS kernel |
| Syscall Handling | Directly by host kernel | Mostly by Sentry; filtered operations passed to host | Handled by guest kernel |
| Primary Isolation Boundary | Linux namespaces, cgroups, seccomp | Sentry, virtualization/ptrace sandbox, seccomp | Hypervisor, virtual devices, hardware virtualization (VT-x/AMD-V) |
| Compatibility | High for standard Linux applications | High for supported scenarios, but incomplete | Full Linux environment compatibility |
| Startup Time | Often under 1 second | Typically 1–2 seconds | ~5–10 seconds in microsrv |
| Memory Footprint | Minimal | Low, depends on workload | Higher due to guest OS and kernel overhead |
| Primary Risks | Kernel flaws, runtime CVEs, misconfigurations | Sentry bugs, host interface vulnerabilities, misconfigurations | Hypervisor vulnerabilities, virtual device bugs, misconfigurations |
Startup times are approximate benchmarks that depend on image size, hardware, disk caching, and execution mode.
gVisor: Extra Defense Without a Full Virtual Machine
In microsrv, containers run with gVisor. Rather than passing syscalls directly to the host kernel, application requests are handled by Sentry, an application kernel written in Go.
This significantly narrows the host kernel attack surface exposed to the workload. For web backends, microservices, and many Python or Node.js jobs, gVisor provides strong defense-in-depth while keeping containers lightweight.
However, gVisor is not a full virtual machine. It does not implement every Linux syscall, and specific low-level operations, custom kernel modules, or nested virtualization scenarios may fail or behave unexpectedly.
KVM: A Dedicated Kernel for Every Sandbox
With KVM, code executes inside a dedicated guest operating system. The guest kernel handles syscalls independently, while interaction with physical hardware and the host system is strictly managed through the hypervisor and virtualized devices.
This does not make vulnerabilities impossible, but it changes the isolation boundary entirely. Escaping a guest VM typically requires compromising hardware virtualization extensions, finding a hypervisor bug, or exploiting an emulated device.
For untrusted code that requires elevated permissions inside its environment, hardware-backed virtualization provides a robust containment layer.
Even so, KVM alone does not guarantee security. Virtual networks, disk mounts, device configurations, and API credentials must be secured, and virtualization components kept up to date.
4. Why an Agent Might Need a Full Linux Environment
An AI coding agent rarely runs a single standalone script. In practice, it explores repositories, installs dependencies, compiles native modules, executes test suites, and debugs failures.
That workflow often requires:
aptand system packages for installing libraries and runtimes;gcc,cargo,go build, ornode-gypfor compiling binaries;systemdfor running and supervising auxiliary background services;- Docker for building and validating container images;
mount, FUSE, and specificioctloperations for virtual filesystems;- Access to kernel parameters or debugging tools for low-level software.
Not every task demands all of these capabilities. A lightweight Python script doesn’t need a full virtual machine. But when an agent needs to manage system dependencies, build images, or launch daemons as it would on a production server, runtime restrictions become a blocker.
While gVisor supports many common development patterns, it is not 100% compatible with raw Linux. Loading kernel modules and performing low-level filesystem or network operations are not supported in standard gVisor containers.
We explored a similar trade-off in our post on hybrid workloads in containers and VMs: CI/CD runners that need Docker-in-Docker or broad system capabilities require VM-level virtualization.
Inside a KVM virtual machine, the agent interacts with a standard Linux kernel and can carry out tasks requiring administrative privileges inside the guest. For example, Docker can run directly inside the guest without exposing the host’s Docker socket.
5. Sandbox Lifecycle in microsrv
Virtual machines have an obvious drawback: they take longer to boot than containers. For an agent issuing hundreds of quick commands, startup latency can add up.
However, a sandbox does not need to be rebuilt from scratch before every shell invocation. It can persist across the task lifecycle, retain its filesystem state between model steps, and sleep while the agent is planning its next move.
Creation: A Ready Virtual Machine in 5–10 Seconds
You can provision a virtual machine using the microsrv console, API, or infrastructure as code. Provisioning typically completes in 5–10 seconds.
Initial provisioning is easily automated via cloud-init. For instance, you can pre-install Docker, build toolchains, and Python environments on the first boot:
#cloud-config
package_update: true
packages:
- docker.io
- build-essential
- python3-pip
runcmd:
- systemctl enable --now docker
- usermod -aG docker ubuntu
This is an example baseline; usernames and package lists vary by distribution. If the agent needs Docker, remember that membership in the docker group grants effective root access inside the guest VM.
Once provisioned, the machine joins your private VPC and can access the internet through eBPF NAT without requiring a public IP address.
Administrative access is handled through the SSH gateway, which lets you connect using a stable hostname:
ssh agent@<sandbox>.msrv.space
This avoids exposing guest port 22 directly to the public internet.
Keep in mind that omitting a public IP does not automatically prevent outbound threats. You still need to enforce VPC security rules, restrict egress destinations, and avoid injecting persistent credentials into the sandbox.
Between Steps: Preserving State and Reclaiming Compute
An agent’s workflow consists of sequential phases: inspect the task, read code, execute commands, analyze outputs, and plan subsequent actions. Between these steps, the virtual machine sits idle.
Rather than running compute continuously, microsrv allows you to enable scale-to-zero mode with state persistence.
In scale-to-zero mode, the VM suspends to a checkpoint during inactivity and reclaims compute resources. When incoming traffic arrives, it wakes in 100–250 ms.
Once awakened, the environment resumes with installed packages, running daemons, and modified files intact. (As with any checkpointing mechanism, long-lived stateful network connections should be designed with reconnection logic).
For deeper architectural details, see our deep dive on serverless VMs.
The operational benefit is straightforward: the agent retains a complete, persistent Linux development environment, but you only pay for compute when it is actively running. Storage and volume costs continue to apply while the instance sleeps.
Long-Running Tasks and Live Migration
Some agent workflows run for extended periods—such as building large codebases, running extensive integration suites, or indexing multiple repositories.
When host maintenance is required, microsrv utilizes live migration. Active memory and running processes are transferred to an alternate host without interrupting ongoing tasks or dropping network connections.
Note that live migration handles planned maintenance; unexpected hardware failures require standard recovery procedures. Replicated storage safeguards persistent disk state across nodes, but does not eliminate the need for backups of critical artifacts.
Teardown: Discarding the Ephemeral Environment
Once a task is finished, delete the sandbox using the web console, API, or OpenTofu.
This prevents temporary environments from accumulating stale packages, orphaned credentials, and leftover build artifacts.
Cleanup should be an automated step in your orchestration pipeline, not a manual chore left for the end of the week.
Be mindful of resource lifecycles: depending on your configuration, attached storage volumes may persist after VM deletion. If you want to keep build outputs, retain the volume; if not, include volume deletion in your cleanup routine.
Managing Sandboxes with OpenTofu
When running sandboxes at scale, declarative infrastructure definitions simplify management. The microsrv OpenTofu provider allows you to define virtual machines and networking as code:
resource "microsrv_vm" "sandbox" {
project_id = microsrv_project.prod.id
region_id = data.microsrv_region.central.id
flavor_id = data.microsrv_flavor.std.id
class = "shared"
name = "agent-sandbox-${var.task_id}"
boot_volume_id = microsrv_volume.boot_disk.id
network_interface_ids = [microsrv_network_interface.eth0.id]
ssh_key_ids = [microsrv_ssh_key.deployer.id]
volume_ids = [microsrv_volume.data_disk.id]
serverless = true
}
Refer to the official provider documentation for current argument specifications and schema definitions.
6. The Agent and the Sandbox Are Different Concerns
In our guide to running Hermes Agent in a container, we deployed the agent itself inside a container: using an official image, storing state on a persistent volume, and exposing the management dashboard via an HTTPS gateway.
This fits naturally alongside virtual sandboxes. The agent orchestrator and the code it executes serve different roles and require different isolation boundaries:
| AI Agent as a Service | Execution Sandbox | |
|---|---|---|
| What Runs | The agent binary, LLM client, and tools | Code retrieved or generated by the agent |
| Lifecycle | Long-running service with persistent state | Single task or bounded ephemeral session |
| Key Priorities | High availability, persistent state, low overhead | Strict isolation, full OS compatibility, ephemeral lifecycle |
| Recommended Runtime | Hardened container (e.g., gVisor) | KVM virtual machine for strong containment |
A practical architecture runs the orchestrating agent inside a secure container, while provisioning a dedicated virtual machine within the same VPC for executing untrusted commands.
The agent dispatches tasks to the sandbox over the private network, collects stdout/stderr, and determines the next step. The sandbox itself has no access to the agent’s internal state, API keys, or sibling workloads.
This separation restricts the blast radius. If generated code attempts to delete system files or execute malicious payloads, the damage is confined to the disposable sandbox without threatening the agent itself.
Architecture alone is not sufficient: you must also enforce dedicated API credentials, tight network security groups, egress filtering, and platform access quotas.
7. Security Checklist for AI Agent Sandboxes
A virtual machine is not automatically secure simply because KVM is enabled. You must constrain its access and plan for compromise scenarios:
- Use dedicated sandboxes per task where feasible. Avoid reusing environments across unrelated tasks to prevent cross-contamination of files, processes, and credentials.
- Never store long-lived secrets inside the sandbox. Pass only task-scoped credentials, and use short-lived tokens whenever possible.
- Enforce automatic environment TTLs. Automatically terminate stale sandboxes and verify that cleanup jobs run reliably.
- Do not expose inbound ports unnecessarily. Rely on the SSH gateway for administration, and protect public HTTP endpoints behind authenticated gateways.
- Restrict egress traffic. If a task does not require internet access, disable outbound networking entirely. If access is needed, filter egress to allowlisted endpoints.
- Never mount host resources. Avoid exposing host Docker sockets, host filesystem directories, or orchestration credentials into the sandbox.
- Collect audit logs externally. Stream command execution logs, network flows, and system events to an external system that the sandbox cannot tamper with.
- Enforce resource limits. Set explicit limits on vCPUs, RAM, disk space, and task duration to prevent runaway processes from consuming infrastructure resources.
- Isolate execution privileges from infrastructure management. An agent executing unit tests should not possess credentials to manage virtual machines or project networking.
- Audit post-task cleanup. Ensure that teardown routines delete attached block volumes, temporary files, and task-specific API tokens along with the VM.
The final point is critical for automated systems: if cleanup requires manual intervention, temporary environments inevitably become unmonitored infrastructure sprawl.
8. When to Use a VM vs. When a Container Is Enough
KVM sandboxes have trade-offs. A virtual machine takes longer to boot than a container, consumes more baseline memory, and incurs virtualization overhead.
For lightweight, tightly scoped workloads—such as running a single pure function or processing structured data in a predefined runtime—a container is often simpler and more cost-effective.
gVisor is well-suited for workloads where standard container isolation is insufficient, but low overhead and standard Linux runtime compatibility are desired.
KVM is the right choice when:
- Code originates from untrusted sources or LLM generation;
- The agent requires system-level packages and elevated guest permissions;
- Workflows depend on Docker-in-Docker or native toolchain compilation;
- Hardware-backed kernel isolation from the host is mandatory;
- The sandbox can be provisioned on demand, suspended during idle time, and discarded upon completion.
For high-security multi-tenant platforms, specialized microVM solutions like Firecracker or Kata Containers offer alternative approaches to running virtualized workloads within container ecosystems.
The guiding rule is to select your runtime based on required privilege levels, trust boundaries, and the blast radius of a potential compromise, rather than assuming one runtime fits every use case.
Summary
Giving an AI agent a shell requires more than dropping it into a basic container. Models make mistakes, prompt injection attacks can hijack agent behavior, and untrusted code may attempt privilege escalation.
Containers and gVisor are great for trusted microservices and standard workloads. But when an agent needs to execute arbitrary code with root access, a dedicated KVM virtual machine provides a far stronger defense boundary thanks to its isolated guest kernel.
In microsrv, you can launch these virtual machines in 5–10 seconds, configure them automatically using cloud-init, suspend them to zero compute during idle steps, and discard them when finished.
This provides the agent with a complete Linux development environment while protecting your underlying infrastructure, secrets, and private network from untrusted actions.
References and Resources
- Docker Engine Security — container isolation mechanisms and security baselines.
- gVisor Documentation — architecture, syscall handling, and limitations.
- Linux KVM Project — kernel-based virtual machine documentation.
- Firecracker (NSDI 2020) — lightweight microVM architecture.
- Kata Containers — virtualization-based container runtime.
- Dirty Pipe (CVE-2022-0847).
- runc Container Escape (CVE-2019-5736).
- VENOM Hypervisor Vulnerability (CVE-2015-3456).
- Hermes Agent in a Container — autonomous agent deployment on microsrv.
- Serverless VMs — scale-to-zero compute and rapid wakeups.
- Hybrid Workloads in a Single VPC — pairing containers with virtual machines.
- Live Migration — zero-downtime workload migration.
FAQ
Can I just use a gVisor container as a sandbox?
Yes, if your agent only runs standard Python or Node.js scripts and does not need restricted system capabilities. gVisor provides substantial defense-in-depth over standard containers. A virtual machine is necessary if you require a dedicated kernel, Docker-in-Docker with administrative privileges, or an unambiguous hardware isolation boundary.
Isn’t spinning up a virtual machine for every task too expensive?
It depends on the instance flavor, duration, and storage footprint. In scale-to-zero mode, you only pay for storage while the machine sleeps between agent decisions, with fast 100–250 ms wakeups. When evaluated against the total runtime of an interactive agent session, serverless VMs are cost-effective compared to over-provisioned static instances.
If the agent runs in a container, why not execute the code there directly?
Because the orchestrating agent and the code it executes have different trust levels. The agent is a trusted, stateful service with access to API keys. The code it executes is untrusted and may be influenced by external prompt injections. Separating them prevents a compromised execution environment from accessing the agent’s credentials or memory.
What stops an agent from deleting its sandbox or interfering with other tasks?
If an agent is given infrastructure management tokens, virtualization cannot prevent it from making unauthorized API calls. Infrastructure management permissions must be strictly isolated from execution environments. Sandboxes should use least-privilege tokens, scoped VPCs, and external TTL cleanup rather than allowing commands inside the sandbox to manage platform resources.
Run serverless VMs, containers, and databases
microsrv offers instant VM & container startup, fast NVMe databases, and included VPC with access gateways for maximum developer convenience.