Infrastructure Review Stack

gVisor vs Firecracker for Untrusted Code Isolation

AI-generated code demands isolation, but gVisor and Firecracker disagree on how.

Senior Writer · · 12 min read
Cover illustration for “gVisor vs Firecracker for Untrusted Code Isolation”
Code Execution Sandboxes Compared · August 19, 2026 · 12 min read · 2,629 words

gVisor and Firecracker both try to keep code you don't trust away from your host, but they take completely different roads to get there. One reimplements the kernel in user space and catches every syscall before Linux ever sees it. The other boots an actual, minimal kernel inside a microVM walled off by the CPU itself. This piece looks at how each mechanism works, where its security boundary actually sits, and what that means once you're the one deciding how to run code you can't fully vouch for.

Every container on a host shares one kernel, and that kernel is the biggest chunk of attack surface you're exposing, full stop. Linux has a sprawling syscall interface; one exploitable bug in any single call can turn into a container escape. Seccomp profiles, AppArmor policies, and capability drops cut down the exposure, but they don't remove it. The structural fact doesn't move: every tenant on the box is one kernel bug away from every other tenant.

That fact matters more now than it did five years ago, because what counts as "untrusted code" has shifted under our feet. A growing share of code running in production wasn't written by someone sitting down to write it; a model generated it, sometimes with no human reading it before it runs. Veracode's 2025 GenAI Code Security Report found vulnerabilities in nearly half of tested AI-generated code tasks, which is not a rounding error. That number turns "just run the agent's output" from a convenience into a decision with actual teeth. Multi-tenant platforms, CI runners, serverless functions, and agent execution environments make the stakes worse: one escaped container doesn't just hurt the tenant who wrote the bad code, it can pivot to the host and from there to everyone else sharing it.

So the practical response that's emerged from running these systems in production is blunt: treat LLM-generated or user-supplied code as hostile whether or not it actually is. Two architectures have grown up around that stance, and they disagree, genuinely, about where the boundary should live and what should be enforcing it.

Venn diagram: gVisor vs Firecracker: Security Boundaries. Compares gVisor and Firecracker; overlap: Shared Goals.

How gVisor interposes a user-space kernel between the application and the host

At the center of gVisor sits the Sentry, and the whole security model hangs on what that thing actually does. When an application inside a gVisor container makes a syscall, it doesn't go anywhere near the host kernel. It goes to the Sentry, a user-space process that reimplements a big chunk of Linux syscalls in Go. The Sentry handles the call itself, internally, and only afterward does it make its own, much smaller set of syscalls to the real kernel underneath. The application is talking to a Go program. That Go program is talking to Linux on its behalf, in a narrow vocabulary it doesn't get to expand.

Filesystem work gets split off entirely, handled by a separate process called the Gofer rather than by the Sentry directly, which adds one more seam even inside gVisor's own architecture. Early versions used a 9P-based protocol for this, and it came with real round-trip cost every time a file got touched. Current versions use something called directfs instead: the Gofer donates file descriptors straight to the Sentry, cutting a lot of that overhead out.

gVisor also ships more than one interception mode, and the mode changes what "isolation" means in your specific environment. Systrap has been the default since 2023. It rides on Linux's seccomp-bpf subsystem and needs no hardware virtualization at all, which is exactly what makes gVisor usable inside VMs, inside managed Kubernetes, in places where you don't own the hypervisor. KVM mode also exists, using hardware virtualization for interception where it's available, with a different performance profile than systrap. Most people running gVisor today are running systrap, so that's the mode worth understanding in detail.

Here's the bet gVisor is making. To reach the host, an attacker first has to find a bug in the Sentry's Go implementation of some syscall, and then still has to operate inside whatever narrow set of host syscalls the Sentry itself is permitted to make. That's two locks instead of one. Is that meaningfully harder? In practice, yes, but the Sentry has had its own vulnerabilities over the years, and that's a fact worth sitting in your threat model rather than waving off. The underlying wager is that a smaller, memory-safe codebase in Go is easier to audit than the entire surface of the Linux kernel, and in production, at real scale, that wager has mostly held.

Operationally, adopting gVisor is easy because it drops in as an OCI-compatible runtime called runsc. It runs under Kubernetes without forcing you to rebuild how containers get built or deployed, and it doesn't need KVM, which matters a lot if you're on bare metal you don't control, or inside nested virtualization where hardware acceleration never reaches you.

How Firecracker draws a hardware boundary around each workload

Firecracker starts from a different place entirely. It boots a real, minimal Linux kernel inside a microVM for every single workload, and the wall between that guest kernel and the host is enforced by the CPU, through Intel VT-x or AMD-V. An attacker who fully compromises the guest kernel gets root, but only inside that VM. Reaching the host from there means an entirely separate hypervisor escape, on top of everything they already did.

Firecracker exposes very little on top of that boundary. It emulates a genuinely small, fixed device set: virtio-net, virtio-block, virtio-vsock, virtio-balloon, a serial console, a keyboard controller. Set that against something like QEMU's full PC emulation, built up over decades to support real hardware compatibility, and the gap in exposed surface is stark. As of March 2026, Firecracker's VMM codebase runs at roughly 83,000 lines of Rust, a memory-safe language chosen specifically to close off the class of bugs (buffer overflows, use-after-free) that have historically been how attackers break out of software boundaries. Each microVM also gets its own VMM process, so a bug that compromises one instance doesn't hand anyone a foothold into the others running next to it.

Sounds good on paper. Who's actually testing whether it holds? The exploit market is a decent proxy. VM escapes sit in a completely different pricing tier from container escapes, with bounties running well into the hundreds of thousands of dollars; Google's kvmCTF program alone prices a full KVM escape at $250,000. That number is a scarcity signal. Hypervisor CVEs exist, nobody's pretending otherwise, but they show up far less often than the kernel bugs behind container escapes, and the bounty market reflects exactly that gap in supply.

Does it hold up outside a lab? AWS Lambda runs on Firecracker, handling over 15 trillion monthly standard invocations. That's one of the largest serverless platforms on the planet running this exact model at a scale that would have surfaced a structural weakness by now if one were there.

Production deployments don't run bare Firecracker either. A wrapper called the Jailer sits around it, applying cgroup and namespace isolation and dropping privileges before the VMM process even starts. Worth saying plainly: Firecracker's security model isn't self-contained. It assumes a correctly configured, hardened host underneath it, and if that assumption breaks, part of the guarantee breaks with it.

Where the security boundary actually sits, and what breaking it requires

Table: gVisor vs. Firecracker: Core Tradeoffs. Compares Isolation Mechanism, What Must Fail to Escape, Startup Latency, Runtime Overhead, and 4 more by gVisor and Firecracker.

So where does each boundary actually sit, in terms of what an attacker has to pull off?

With gVisor, an attacker needs to compromise the Sentry, meaning find and exploit a bug in its Go syscall implementation, and then operate inside whatever narrow host syscall set the Sentry has access to. The Sentry runs as a process on the host. It's sandboxed heavily, but it isn't hardware-isolated. The boundary is enforced by software correctness, full stop. Seccomp filters, cgroups, namespaces, and capability restrictions add friction at each step along that path, but none of them changes the basic shape of the thing: software watching software.

With Firecracker, an attacker who fully compromises the guest kernel gets root inside that VM and stops there. Getting to the host means finding a bug in the VMM itself or in KVM, a class of vulnerability that is both rare and, per the bounty numbers above, expensive precisely because it's rare. That boundary is enforced by the CPU, independent of whether some piece of software happened to be written correctly. That structural difference is the whole point of choosing Firecracker in the first place.

So what does this mean for what you actually build? For workloads where tenant isolation is the entire ballgame (AI agents executing arbitrary user- or model-generated code, shared CI runners, code execution platforms open to the public), Firecracker's hardware boundary is the stronger structural guarantee, and it isn't close. gVisor fits better when the threat is a sophisticated application-level attack that a reduced syscall surface can plausibly contain, rather than a case where you have to assume the worst about everything the code might try. Which threat model are you actually facing? That's the question underneath the choice, and it usually comes down to whether the code running inside is merely unverified or genuinely adversarial.

Performance tradeoffs: where each approach pays its cost

Diagram: Performance Cost: When You Pay and How Much. Visualizes: Contrast the cost shape of the two approaches across three dimensions: (1) per-operation overhead — gVisor syscalls run 2–11× slower than native (USENIX 2019), Firecracker…

Every isolation layer costs something. Where that cost shows up, and whether your workload's shape makes it painful or invisible, is the part worth working out before you commit.

gVisor's overhead lives in the syscall path, paid continuously, on every call. A 2019 USENIX study measured syscall operations running 2 to 11 times slower than native, depending on platform and the specific call in question. Systrap has narrowed that gap a lot since becoming the default in 2023, but syscall-heavy, I/O-heavy workloads remain the place where gVisor's tax adds up fastest. A CPU-bound job that barely touches the kernel hardly notices gVisor is there at all; the overhead isn't uniform, and that unevenness is the thing to actually plan around. Typical startup latency runs around 50 to 100 milliseconds.

Firecracker's cost story is close to the mirror image: front-loaded, paid once, at boot. Cold start runs 100 to 200 milliseconds, and once the microVM is up, CPU and memory performance sits close enough to native that the per-operation tax from hardware virtualization is negligible. Snapshot-and-restore pushes this further. Pre-warmed snapshots can bring perceived boot time down into the tens of milliseconds, which matters enormously for anything that has to spin up on demand.

Memory tells its own story. Firecracker adds a small, fixed overhead per instance, and at thousands of concurrent instances that adds up to something like a 10 to 20% cost bump over plain containers. Expensive? Depends what you're weighing it against. For AI agent workloads that already need substantial memory allocations, the VMM's fixed overhead shrinks proportionally as application memory dominates the total. The density penalty is real, but it's bounded. A multi-tenant breach is unbounded, and that asymmetry is worth sitting with for a minute before you decide the density cost is too high.

GPU access is where gVisor runs into an actual wall, a harder limit than the per-syscall tax. Its syscall interception layer blocks direct PCIe passthrough, so GPU access from inside a gVisor container is restricted in ways that matter a lot for inference workloads. Firecracker's hardware virtualization path supports VFIO device passthrough, which opens the door to GPU-accelerated work running inside a microVM. For AI agent tasks leaning on inference, this isn't a footnote. It's often the whole decision.

Syscall compatibility and what it means for workload portability

The Sentry reimplements enough of the Linux syscall surface to run most common applications without a hitch. But "most" is doing real work in that sentence: workloads relying on systemd, Docker-in-Docker setups, certain kernel modules, or less common networking capabilities may not run under gVisor at all, and sometimes they fail silently instead of throwing a clean error. The practical advice here isn't complicated. Test your specific workload against gVisor's syscall compatibility list before betting production on it, and don't assume "it's a container, so it'll work" carries over automatically.

Firecracker sidesteps the whole problem at the application layer, because every microVM boots a real, complete Linux kernel. The guest sees Linux, full stop, so syscall compatibility just isn't a question you have to ask. The tradeoff moves up a layer instead, into infrastructure: Firecracker needs KVM, which means bare metal or nested virtualization support. That's not available everywhere, including some managed environments and, notably, on macOS development machines.

What does this mean day to day? gVisor's OCI compatibility through runsc makes it a low-friction addition to an existing Kubernetes or container workflow; your tooling doesn't have to change at all. Firecracker asks for more orchestration work up front: provisioning microVMs, managing snapshots, handling networking at the VM layer. That work buys you full Linux compatibility and a materially stronger security boundary in exchange. For AI agent platforms running code you genuinely can't predict, that tradeoff tends to favor Firecracker, because gVisor's coverage gap stops being a compatibility footnote and starts being a reliability risk the moment you can't know in advance which syscalls the agent's generated code is going to invoke.

How to match isolation approach to workload requirements

This isn't really about crowning a winner. It's about matching the tool to the threat actually in front of you, and the two approaches suit genuinely different situations.

gVisor makes sense for workloads that are syscall-light and CPU-bound, where the per-syscall tax never gets much chance to pile up. It also fits environments where KVM simply isn't available: managed Kubernetes clusters, nested VMs, CI runners that don't expose hardware virtualization to you. Teams that want a drop-in OCI runtime with minimal orchestration changes, and that are willing to actually verify their workloads against gVisor's syscall coverage instead of assuming it, are the right audience here. This suits defense against application-level attacks from code that's mostly trusted but not fully verified, rather than full adversarial execution where you have to assume the worst going in.

Firecracker fits multi-tenant platforms where tenant isolation is the primary requirement and a hardware-enforced boundary isn't optional. It also suits workloads that are I/O-heavy or syscall-intensive, or that need full Linux kernel compatibility because you genuinely cannot predict what the code inside will try to do, which describes a lot of AI-generated code fairly well. Add GPU-accelerated inference or training, where device passthrough matters, and Firecracker is doing something gVisor structurally cannot. Long-running agent workflows benefit too: snapshot-and-restore lets an agent pause mid-task and pick back up later without losing state, a real operational win for anything that isn't short-lived. The threat model here is genuinely adversarial or untrusted code, where a guest kernel compromise absolutely cannot become a path to the host.

Some platforms don't pick one and call it a day; they layer both. gVisor handles tenant-level application isolation as a first line, while Firecracker microVMs get reserved for the highest-risk execution contexts, the code nobody's willing to vouch for at all. That's defense-in-depth spread across layers instead of stacked within one, and it's a sound answer when different parts of the same platform carry genuinely different risk.

Isolation isn't a single dial you turn up or down. It's a decision about where the boundary sits and what has to fail before it breaks. gVisor bets on a smaller, auditable software surface standing between the application and the kernel; Firecracker bets on the CPU itself simply refusing to let the guest touch anything past its walls. Both bets have paid off in production, at real scale, for real companies running real traffic. The job in front of you is being honest about what your workload actually does and what you can't afford to have go wrong, not declaring one of these categorically better than the other.

Sources

  1. northflank.com
  2. alekseialeinikov.com
  3. stealthcloud.ai
  4. softwareseni.com
  5. edera.dev

More in Code Execution Sandboxes Compared