The Sandbox Comparison
Sandboxing in computing is a security mechanism that runs programs (or code) in a tightly controlled, isolated environment. The goal is to limit what the code can access—files, network, processes, devices, or the host system—so faults, bugs, or malicious behavior stay contained and cannot harm the rest of the machine or other workloads.
Common uses include testing untrusted code, malware analysis, multi-tenant cloud services, browser tabs and apps, and running AI-generated or agent-driven code safely. With agent development taking off, sandboxes are showing up everywhere again—and the design choices matter more than the marketing labels.
I have worked with Linux and containers for a while, and this topic pulled me in. This post is my dig into the fundamentals and a side-by-side look at the common options, so you can build a clearer mental model of what “sandbox” actually means.
Core fundamentals and isolation
Isolation is not binary. It sits on a spectrum of strength vs. overhead, startup speed, compatibility, and operational complexity. Key building blocks:
- Namespaces + cgroups + seccomp + capabilities (Linux kernel features): Give a process its own view of PIDs, mounts, network, users, etc.; limit CPU/memory; filter system calls; and drop privileges. Shared host kernel.
- chroot / jails: Restrict the filesystem root.
- User-space interception: Re-implement or filter syscalls outside the real kernel.
- Hardware virtualization (KVM, Hypervisor.framework, etc.): Run a separate guest kernel so the host kernel is never directly exposed.
- Language/runtime boundaries: WASM/WASI, V8 isolates, JVM sandboxes—memory-safe and capability-based, but limited to what the runtime exposes.
- Rule-based / mandatory access control: SELinux, AppArmor, Landlock, capability tokens.
The isolation spectrum
From weaker/faster to stronger/heavier:
- None / workspace only (e.g. git worktree) — no real execution boundary.
- Language/runtime (WASM, V8 isolates) — good for pure in-process code; breaks on native shells or FFI.
- Kernel confinement / process sandboxes (seccomp + Landlock + namespaces): Bubblewrap, Firejail, nsjail. Minimal overhead, Linux-focused.
- Containers (shared kernel): Default runc-style. Hardened setups (rootless Podman, dropped capabilities, read-only rootfs, user namespaces) improve this substantially.
- Userspace kernel: gVisor (Sentry intercepts and reimplements many Linux syscalls in Go; Netstack for networking). Stronger than plain containers without full virtualization.
- Lightweight / microVMs: Own guest kernel via a minimal hypervisor. Hardware-enforced isolation, fast boots.
- Full VMs: Traditional QEMU/KVM, cloud instances—maximum isolation, highest cost.
Key technologies and alternatives
Container style
These look like traditional containers and share a few traits:
- They share the host kernel.
- Isolation comes from Linux namespaces, cgroups, capability dropping, seccomp filters, and (ideally) running rootless.
- They are fast and low-overhead, but weaker than optimized sandboxes such as microVMs (e.g. Firecracker).
Common options:
- Podman, Docker, LXC/LXD — traditional container runtimes and tools.
- Bubblewrap, Firejail, nsjail — process-level sandboxes using much of the same kernel machinery under the hood.
- Hardened / custom runtimes — runc and containerd as the low-level OCI layer. Others build sandboxes on top of these (or similar primitives), e.g. various agent sandbox runners and open-source sandbox projects.
Userspace style: gVisor
gVisor adds an extra isolation layer between a containerized application and the host Linux kernel, reducing the damage an escaped or malicious workload could cause.
A normal container makes system calls directly to the host kernel:
|
|
With gVisor:
|
|
The application believes it is talking to Linux, but most of its system calls are intercepted and implemented by gVisor’s userspace kernel, called the Sentry.
That gives an attacker two isolation boundaries to cross:
- Escape from the application into gVisor.
- Escape from gVisor into the host kernel.
Pros vs. plain containers: stronger isolation—this is the main win.
Cons:
- Syscall-heavy apps pay a performance cost.
- Filesystem and networking can add overhead.
- Apps that need uncommon kernel modules or features may not work without changes.
MicroVM / lightweight VM runtimes
These dominate high-security and AI-agent sandboxing because they combine container-like density and speed with VM-grade isolation (own guest kernel, hardware isolation):
- Firecracker (AWS, open source): Minimal VMM designed for serverless. ~125 ms boot, ~5 MB overhead, high density. Powers many commercial AI sandboxes. Limited device model (optimized for security and speed).
- Kata Containers (CNCF): Runs each container/pod inside a lightweight VM while keeping the familiar OCI/Kubernetes interface. Can use Firecracker, Cloud Hypervisor, or QEMU underneath. Strong fit for production Kubernetes multi-tenancy, full Linux compatibility, and optional GPU paths.
- libkrun, Cloud Hypervisor, Unikraft, Apple’s containerization (VM-per-container on Apple silicon), and related projects: Variations focused on embeddability, even lower overhead, macOS support, unikernels, or better developer experience.
Comparison table
| Technology | Isolation model | Shared host kernel? | Typical startup | Overhead | Own Docker daemon? | Best for | Notes |
|---|---|---|---|---|---|---|---|
| Docker Engine (classic) | Namespaces + cgroups + seccomp | Yes | <1 s | Very low | Host’s | General containers, trusted code | Needs heavy hardening for sandbox use |
| Podman | Namespaces + cgroups + seccomp | Yes | <1 s | Very low | No (rootless) | Rootless container sandboxes | Safer defaults than classic Docker |
| runc / containerd | Low-level OCI runtime | Yes | Near-instant | Minimal | No | Building custom sandboxes | Foundation under Docker and Podman |
| Bubblewrap / Firejail / nsjail | Process namespaces + seccomp | Yes | Near-instant | Near-zero | No | Lightweight single-process sandboxes | No full container image required |
| gVisor | Userspace kernel (syscall interception) | Partial | Sub-second | Medium | No | Stronger container isolation | Drop-in runtime for Docker/K8s |
| Firecracker / Kata / libkrun | MicroVM (own guest kernel) | No | ~100–300 ms | Low (~5–50 MB) | Depends | High-security untrusted code | Hardware-level isolation |
Docker Sandboxes (sbx) |
MicroVM (own Linux kernel) | No | Seconds (after first pull; faster after) | Low | Yes (private daemon inside the VM) | AI coding agents on local machines | Cross-platform (macOS / Windows / Linux). Agent gets full Docker inside the sandbox while the host stays isolated. Network policies + credential proxy included. |
Looking across the table, microVMs win on isolation while still keeping startup and memory overhead practical. Plain containers win on familiarity and raw speed; gVisor sits in the middle as a stronger shared-kernel option.
Most of this map will feel familiar if you already live in containers—Firecracker, Kata, and Apple’s libkrun-style path are the pieces worth fresh attention for agent workloads.
Closing thought: if sandboxes are strong, why do agents still escape?
That is the uncomfortable question behind the recent agent-escape stories. If products claim microVMs, hardened runtimes, and “enterprise isolation,” how does the agent still break out?
Usually it is not that the agent is magically smarter than the hypervisor. Escapes more often come from what we put around the sandbox:
- overly broad mounts and secrets
- network and tool access that outruns the threat model
- weak boundaries between the agent, the host, and third-party tools
- assuming “we use Firecracker / gVisor / a container” is enough without hardening the rest of the stack
Isolation tech is real. The failure mode is often policy and product design, not the absence of a sandbox label. That is the part worth watching as agent sandboxes keep multiplying.
Comments