Sandboxing untrusted AI agents on Linux A Linux sandbox for untrusted AI coding agents is a stack of partial mechanisms — cgroup v2, user and other namespaces, mount namespace with pivot_root, capabilities plus no_new_privs, Landlock and seccomp-bpf — that all share one host kernel, so a single kernel vulnerability reachable from the sandbox is a full escape, according to an analysis dated late October 2026. The strongest boundary is a second kernel, meaning a virtual machine, which the analysis says is why serious hosted products are microVMs and why OS-level tools such as Landlock, seccomp and bubblewrap are best kept for code you mostly trust on a machine you control. The analysis identifies network egress as the hardest layer to get right, citing exfiltration of secrets, reaching internal services and hitting the cloud metadata endpoint at 169.254.169.254 as the damaging outcomes. An AI coding agent runs code before any human has reviewed it: shell commands, generated scripts, pip and npm installs, tool plugins. It can be steered by prompt injection https://genai.owasp.org/llmrisk/llm01-prompt-injection/ hidden in a web page or a dependency, and even a well-meaning agent can rm -rf the wrong tree. AI review agents exist, but they mostly read the diff after the code has already run, and they are LLMs that the same prompt injection can fool, so they complement a sandbox rather than replace it. So what does a sandbox for that code actually have to do on Linux, and why is “minimal” so hard? 📝 TL;DR A Linux sandbox is a stack of partial mechanisms that all share one host kernel . Each layer stops one class of thing and nothing else, and there is no single switch. The strongest boundary is a second kernel , which means a virtual machine. That is why the serious hosted products are microVMs, and why the OS-level tools Landlock https://docs.kernel.org/userspace-api/landlock.html , seccomp, bubblewrap https://github.com/containers/bubblewrap are best kept for code you mostly trust on a machine you control. The mechanisms involved, in the order a launcher typically applies them. They are not ranked: each answers a different question. | Layer | Question it answers | What it does not stop | |---|---|---| | cgroup v2 https://docs.kernel.org/admin-guide/cgroup-v2.html | how much ? | anything within quota; not a security boundary | | user namespace https://man7.org/linux/man-pages/man7/user namespaces.7.html | who am I? | kernel bugs reachable by unprivileged users | | pid/net/ipc/uts namespaces https://man7.org/linux/man-pages/man7/namespaces.7.html | what can I see ? | the shared kernel behind every view | | mount namespace + pivot root https://man7.org/linux/man-pages/man2/pivot root.2.html | what filesystem ? | files under the roots you granted | | capabilities https://man7.org/linux/man-pages/man7/capabilities.7.html + no new privs https://docs.kernel.org/userspace-api/no new privs.html | can I re-privilege ? | syscalls that need no privilege | | Landlock | which paths , TCP/UDP ports, unix sockets, signals? | anything outside the rights it handles; most syscalls | | seccomp-bpf https://docs.kernel.org/userspace-api/seccomp filter.html | which syscalls ? | anything an allowed syscall can reach | Everything here is point-in-time late October 2026 . Details of products and papers move monthly, so verify specifics before relying on them. 🚧 1. The current challenges 📚 One shared kernel is the whole problem. Namespaces, cgroups, capabilities, seccomp and Landlock all run in the host kernel. A single kernel vulnerability reachable from the sandbox is a full escape. The Linux syscall surface is enormous hundreds of syscalls, each with many argument shapes , and features like io uring https://man7.org/linux/man-pages/man7/io uring.7.html add surface. Enabling unprivileged user namespaces, which you need to sandbox without root, itself exposes more kernel code to untrusted callers and has been a recurring source of local privilege-escalation CVEs. 🎮 Agents need capability, which fights confinement. A file-only agent is easy to box. A useful coding agent wants to install packages network , spawn compilers and test runners exec and many syscalls , read large parts of the filesystem, and sometimes use GPUs. Every capability you grant is attack surface you re-open. The art is least privilege per task , which is exactly what is hard to specify up front. 🧱 Network egress is the real prize, and the hardest to get right. The damaging outcomes are network actions: exfiltrating secrets, reaching internal services, hitting the cloud metadata endpoint 169.254.169.254 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html , pulling a malicious payload. A binary on/off switch blocking AF INET sockets in seccomp is too coarse for an agent that must reach a package registry. A filtering proxy is the right tool, but it needs TLS interception or a domain allow-list, plus care that the agent can’t just talk to localhost services or use DNS as a covert channel. 🗒️ Secrets and ambient authority leak in surprising ways. Environment variables, inherited file descriptors, cloud instance-metadata credentials, ~/.aws , ~/.ssh , a mounted Docker socket, a GITHUB TOKEN in the environment: none of these are “files the agent opened”, so a filesystem sandbox alone misses them. A 2026 security note on AWS Bedrock AgentCore argued that its code-interpreter microVM still exposes execution-role credentials via the metadata service; AWS considers that by design. Whoever is right, the lesson stands: isolation of the compute does not imply isolation of the credentials . 🐳 Views leak the host. Inside a container, /proc/cpuinfo , /proc/meminfo and /proc/stat show the host’s numbers unless something virtualises them lxcfs https://github.com/lxc/lxcfs . That is the same reason top in a container shows host CPU and steal time. Information disclosure is a weaker threat than escape, but it feeds fingerprinting and side channels. 📦 Correctness is a sequencing minefield. The layers have prerequisite chains and failure modes. no new privs must be set before an unprivileged seccomp filter. A gid map needs setgroups=deny . A bind mount can’t go read-only in one step on older kernels. Landlock rights must be masked to the running ABI or restrict self fails. Seccomp goes in last, so your own setup syscalls aren’t filtered. Each is a place to silently under-confine, and a half-applied sandbox is worse than none , because you think you’re protected. A good sandbox aborts on any layer that fails rather than running the agent half-confined. 🐧 Deny-lists have traps. A syscall deny-list is deceptively easy to under-build: - 🧱 io uring. It can perform socket, connect and openat operations as ring operations , without issuing those syscalls, so a naive seccomp network block is sidestepped by an agent that opens a ring and connects through it. Any deny-list that ignores io uring is porous. - 🔑 The x32 ABI https://lwn.net/Articles/456731/ . On x86-64, x32 syscalls carry the same AUDIT ARCH X86 64 token but OR 0x40000000 into the number. A filter that only compares plain numbers lets the x32 variant of every denied call through. - 📦 ioctl TIOCSTI https://man7.org/linux/man-pages/man2/TIOCSTI.2const.html . A process sharing the controlling terminal can push bytes into the terminal’s input queue, and the parent shell runs them after the sandbox exits. That is a full escape that touches no file and opens no socket. Since Linux 6.2 the host can switch it off with sysctl dev.tty.legacy tiocsti=0 , and several distributions ship it off, but a sandbox should still call setsid https://man7.org/linux/man-pages/man2/setsid.2.html and filter the ioctl itself. - 🔹 Arch confusion. A 32-bit i386 calling convention uses different numbers for different calls, so a filter must check the architecture first. Each hole is invisible if you reason about syscalls by name. This is why serious sandboxes invert to deny-by-default and lean on audited, maintained profiles instead of a hand-rolled list. 📝 Portability and kernel-version drift. Landlock needs Linux 5.13 or newer and grows new abilities per ABI: TCP bind and connect by port ABI 4, Linux 6.7 , device ioctls ABI 5 , abstract-unix-socket and signal scoping ABI 6, Linux 6.12 , audit logging ABI 7 , pathname unix sockets ABI 9 and UDP ABI 10 . A sandbox written for ABI 10 quietly gets less on a 6.6 LTS kernel unless it checks. Seccomp syscall numbers are per-architecture. Unprivileged user namespaces are disabled on some hardened distributions, and from Ubuntu 24.04 AppArmor https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces restricts them kernel.apparmor restrict unprivileged userns=1 , which breaks bubblewrap unless a profile grants it userns . A sandbox that works on your machine may fail open elsewhere. 🔥 Performance and density. Hosted agent platforms run many sandboxes and want sub-second cold starts and snapshot/restore. OS-level sandboxes are cheap microseconds to milliseconds but weak. VMs are strong but were historically slow to boot, which is the gap Firecracker plus snapshotting closed, and why microVMs became viable for this at all. 🔮 2. Where the future is moving - 🔥 MicroVMs are becoming the default for untrusted code, not the exception. Firecracker https://firecracker-microvm.github.io/ -style microVMs give each sandbox its own kernel at roughly 100 to 150 ms cold start, and snapshot/restore lazy page-fault-driven restore via userfaultfd https://docs.kernel.org/admin-guide/mm/userfaultfd.html makes per-task or per-step forking cheap. The hosted market E2B, Vercel Sandbox, AWS AgentCore has largely standardised on this. - 📝 A tiered “right-sized isolation” model is winning over one-size-fits-all. Guidance is converging across 2026 write-ups: OS-level confinement Landlock, seccomp, bubblewrap for trusted code on trusted machines; gVisor https://gvisor.dev/docs/ as a middle tier; microVMs and Kata https://katacontainers.io/ for untrusted, multi-tenant code. The interesting engineering is in choosing and composing tiers per workload, not in one perfect sandbox. - 📦 Landlock is maturing into a real agent primitive. It began filesystem-only Linux 5.13 . ABI 4 Linux 6.7 added TCP bind and connect rules, ABI 6 Linux 6.12 added abstract-unix-socket and signal scoping , and ABIs 9 and 10 added pathname unix sockets and UDP. That turns Landlock from “restrict files” into “restrict a process tree’s whole resource reach”, unprivileged and self-applied, which is ideal for a CLI agent that sandboxes itself. - 🛂 seccomp-notify https://man7.org/linux/man-pages/man2/seccomp unotify.2.html supervisors put user-space policy in the loop. Instead of a static allow/deny BPF program, the kernel can forward a syscall to a supervisor process that decides at runtime and can even virtualise the effect. Sandlock Wang and Zheng, arXiv:2605.26298 https://arxiv.org/abs/2605.26298 , a 2026 research prototype that is now an open-source project https://github.com/multikernel/sandlock section 4 , combines Landlock and seccomp with a seccomp-notification supervisor to get dynamic network decisions, HTTP-level access control, and TOCTOU https://cwe.mitre.org/data/definitions/367.html -safe inspection of execve arguments, all unprivileged, with about 5 ms startup overhead. “Static policy compiled into the kernel, plus a narrow supervisor for the hard cases” is likely where lightweight agent sandboxes head. NVIDIA’s OpenShell section 4 now ships this shape as a product. - ☸️ Orchestration is standardising. The Kubernetes SIG’s agent-sandbox a Sandbox CRD https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/ with warm pools, delegating isolation to gVisor or Kata via RuntimeClass https://kubernetes.io/docs/concepts/containers/runtime-class/ signals that “a sandbox” is becoming a first-class, schedulable object with stable identity, persistent storage and a sub-second claim from a pre-warmed pool, rather than an ad-hoc docker run . - 🧊 Snapshotting is a product feature, not just a speed trick. Pause/resume, fork-a-running-state, and “close your laptop, the agent keeps going” AWS AgentCore are becoming table stakes. That pushes toward VM-level isolation, because snapshotting a whole guest is cleaner than checkpointing a process tree CRIU https://criu.org/Main Page is fragile . - 🔌 Egress control moves up the stack. The trend is away from “block all sockets” toward identity-aware filtering proxies with per-domain allow-lists and audit. Agents must reach some network, and the useful policy is about where , not whether . 💡 3. Contenders vs the status quo The status quo for running arbitrary code has been OCI https://github.com/opencontainers/runtime-spec containers Docker and runc https://github.com/opencontainers/runc : namespaces, cgroups, a default seccomp profile and dropped capabilities. They have good ergonomics and a huge ecosystem, but they share a kernel, so they are insufficient for genuinely untrusted, multi-tenant code. The contenders differ mainly in where the trust boundary sits . | Approach | Boundary | Isolation strength | Start | Cost / density | Best fit for agents | |---|---|---|---|---|---| | chroot | path resolution only | ~none escapable | instant | free | not a sandbox | | bwrap / nsjail https://github.com/google/nsjail / Landlock launchers e.g. Sandlock | namespaces, shared kernel | low to moderate | ~ms | very high | trusted code; per-call confinement | | OCI container runc | namespaces + seccomp, shared kernel | moderate | ~100 ms | very high | semi-trusted; the status quo | | gVisor | user-space kernel intercepts syscalls | high small host surface | ~100 to 300 ms | high | untrusted code without a VM; some compatibility cost | | Incus https://linuxcontainers.org/incus/introduction/ container system container | namespaces + seccomp + LSM, shared kernel | moderate | ~1 ms to 1 s | very high | semi-trusted agents that want a whole persistent OS; self-hosted dev and CI | | Kata / Firecracker / Cloud Hypervisor https://www.cloudhypervisor.org/ | separate guest kernel KVM | highest on Linux | ~100 to 150 ms, faster from snapshot | moderate | untrusted, multi-tenant: the serious default | | WASM https://webassembly.org/ runtime | capability-based VM, no syscalls | high for what it supports | ~ms | very high | narrow, pure-compute tools | Moving down the table trades density and compatibility for isolation strength . Containers sit in the middle and are fine for code you mostly trust. The direction of travel for untrusted agent code is toward gVisor and especially microVMs, with OS-level tools relegated to the innermost layer or to trusted single-user setups. A few nuances the table flattens: - 🖥️ gVisor vs microVM isn’t strictly “weaker vs stronger”. gVisor shrinks the host syscall surface to a few dozen but adds its own smaller kernel’s surface and some workload incompatibility. A microVM gives a full, familiar kernel per guest, but a larger in-guest surface, and the KVM/ virtio https://docs.oasis-open.org/virtio/virtio/v1.3/virtio-v1.3.html boundary is the thing to trust. - 📦 WASM is the strongest per-feature boundary no ambient syscalls at all , but it can only run what has been compiled to it and wired to explicit host capabilities. It is great for a sandboxed function, not for “run this arbitrary repo’s test suite”. - 🐳 Composition beats any single row. Real systems stack them: OS-level confinement inside a container inside a microVM, with a filtering proxy on egress. Each layer catches what the one inside it missed. 📦 4. How leading systems sandbox untrusted AI agents Two families, by where they run. 🤖 Local coding-agent CLIs the OS-level tier - 📝 OpenAI Codex CLI https://developers.openai.com/codex/security . On Linux it uses Landlock and seccomp : Landlock restricts the filesystem to user-approved directories, and seccomp blocks outbound network by default. A newer path vendoring bubblewrap sits behind a feature flag. On macOS it uses Seatbelt sandbox-exec . Its docs warn that inside Docker the needed APIs may be unavailable and sandboxing can fail, which is the portability problem from section 1 made concrete. - 📝 Claude Code https://code.claude.com/docs/en/sandboxing . Anthropic’s sandbox-runtime uses bubblewrap on Linux for filesystem isolation and an empty network namespace. The only way out is an HTTP proxy HTTP and HTTPS and a SOCKS5 https://datatracker.ietf.org/doc/html/rfc1928 proxy other TCP on the host, reached through unix sockets bind-mounted into the sandbox and bridged by socat , which gives domain-level egress control. A seccomp filter blocks other unix sockets on x86-64 and arm64; without it, unix sockets stay open with a warning. On macOS it uses sandbox-exec . By default it warns and runs unsandboxed if dependencies are missing, with a failIfUnavailable hard-fail mode for managed deployments. That is the “fail open vs fail closed” decision made visible. - 🐳 Gemini CLI https://geminicli.com/docs/cli/sandbox/ . The sandbox is opt-in off by default and pluggable: macOS Seatbelt, or Docker, Podman, gVisor or LXC containers. It mainly limits the filesystem to the project directory. These share a fundamental limit that several guides state: bubblewrap and Seatbelt run on the same kernel as the host, so they offer little against kernel exploits. They are suitable mainly for trusted code on trusted machines, the right tool for a developer running an agent on their own laptop and not for a multi-tenant service executing strangers’ code. 🧊 Hosted execution platforms VM or user-space-kernel tier - 🔥 E2B https://e2b.dev/docs . Each sandbox is a Firecracker microVM with its own kernel. The core is Apache-2.0 and self-hostable, with roughly 150 ms cold start from snapshot, and snapshot-based pause/resume is central. It is widely treated as the reference open option. - 🔥 Vercel Sandbox https://vercel.com/docs/vercel-sandbox . Firecracker microVMs , with snapshots and time-limited sessions. - 🎮 Modal https://modal.com/docs/guide/sandbox . Sandboxes default to gVisor , with a VM runtime own kernel added for stronger isolation, and filesystem-snapshot persistence. A standout for GPU inside the sandbox. - 🧊 AWS Bedrock AgentCore Code Interpreter https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/code-interpreter-tool.html . A per-session isolated Linux microVM with a persistent workspace and “keep running while your laptop is closed” semantics see the credential-exposure critique in section 1 . - 🐳 Cloudflare Sandbox SDK https://developers.cloudflare.com/sandbox/ . Built on Cloudflare Containers , one sandbox per VM. Its docs recommend per-user sandboxes because everything in one sandbox shares resources. Third parties dispute the exact mechanism, and it is pre-1.0. - 🐳 Daytona https://www.daytona.io/docs/ . Fast-create persistent workspaces with snapshots and forks. Default isolation is reported as containers on the host kernel, with optional Kata or Sysbox for stronger isolation. Licensing and status were in flux in 2026, so verify before relying on it. - ☸️ Kubernetes agent-sandbox https://agent-sandbox.sigs.k8s.io/docs/getting started/overview/ . Not an isolator itself: a Sandbox CRD plus controller that schedules pods onto gVisor or Kata via RuntimeClass , with warm pools for sub-second starts. It is the orchestration story for self-hosting agent sandboxes at scale. - 🏠 Incus https://linuxcontainers.org/incus/introduction/ . The community fork of LXD Apache-2.0, written in Go . Not agent-specific, but the most credible self-hosted way to hand an agent a whole machine. One REST API and CLI manage system containers shared kernel, unprivileged by default and QEMU virtual machines own kernel side by side, with images, snapshots, copy-on-write clones, projects to partition tenants, network ACLs for egress, and lifecycle events you can subscribe to for audit. The isolation depends on the instance type you pick: a container is the shared-kernel tier, an Incus VM is the separate-kernel tier with QEMU’s larger device surface than Firecracker’s. It is a manager, not a sandbox primitive, so you still put the agent’s tool calls behind your own broker and an egress proxy. 🐚 NVIDIA OpenShell: the supervisor pattern, productised OpenShell https://github.com/NVIDIA/OpenShell is NVIDIA’s answer to agent sandboxing. It was announced at GTC on 16 March 2026 https://investor.nvidia.com/news/press-release-details/2026/NVIDIA-Ignites-the-Next-Industrial-Revolution-in-Knowledge-Work-With-Open-Agent-Development-Platform/default.aspx as part of the NVIDIA Agent Toolkit, released under Apache-2.0, and is at version 0.1.x as of October 2026. It sits between the two families above: it runs on a laptop like the local CLIs, but it is built as a control plane for fleets of agents, like the hosted platforms. It does not replace an agent CLI. It wraps one: the docs and NVIDIA’s own write-ups list Claude Code, Codex, OpenCode and GitHub Copilot CLI as workloads. 🦀 Three components. The architecture https://docs.nvidia.com/openshell/latest/about/architecture splits trust three ways: - The gateway is the control plane. It manages sandbox lifecycle, authenticates users, stores state, delivers policy and attaches credentials “providers” . It is the only component that signs credentials, and each credential is bound to one sandbox and one run. - The supervisor is the trusted side of the boundary. It checks every request against policy, resolves DNS, adds credentials, and opens approved connections itself. It “makes the decisions”. - The sandbox shares the boundary with the untrusted agent. It launches the agent as a child process, identifies which program is making each call, and forwards TCP and DNS to the supervisor. It “never makes policy decisions”. The supervisor and sandbox talk over one mutually authenticated HTTP/2 connection, carried over a unix socket Docker, Podman , TCP Kubernetes or vsock https://man7.org/linux/man-pages/man7/vsock.7.html microVM . 📦 The kernel mechanisms are the ones in this post. Per the support matrix https://docs.nvidia.com/openshell/latest/about/support-matrix , launching a sandbox requires: - 🧱 Landlock ABI 3 or newer Linux 6.2 for the filesystem policy. - 🔑 seccomp user notification , including nested filters and SECCOMP IOCTL NOTIF ADDFD https://man7.org/linux/man-pages/man2/seccomp unotify.2.html with SECCOMP ADDFD FLAG SEND , used to intercept TCP opens and DNS queries. ADDFD is how a supervisor installs a file descriptor it opened into the confined process, the same fd-delegation idea as Capsicum’s broker in section 7. - 🐧 Reading the child’s memory with process vm readv https://man7.org/linux/man-pages/man2/process vm readv.2.html or /proc/