Firecracker vs gVisor: How Each Isolates Untrusted Code, and Why Sprites Run on Firecracker

Firecracker vs gVisor: How Each Isolates Untrusted Code, and Why Sprites Run on Firecracker

Author
Daniel Botha
Daniel Botha
Writer at Fly.io
Published

Firecracker isolates untrusted code by giving it a separate guest kernel inside a hardware-virtualized microVM, while gVisor isolates it by intercepting its system calls in a userspace kernel written in Go, so the two defend against different failures at different costs. On Fly.io, every Sprite is a hardware-virtualized Firecracker microVM with its own Linux kernel; its outbound network is open until you apply a network policy, and its filesystem is a persistent ext4 disk.


You have code you did not write and cannot review: a customer’s build step, a student’s submission, or the Python an LLM just generated from a user’s prompt. It must not reach the host kernel or the other tenants on the box. A plain container shares that kernel with all of them.

Firecracker is the microVM under AWS Lambda.[1] gVisor lists Google Cloud Run, GKE Sandbox and the code execution inside claude.ai among its users.[2]


What Is the Difference Between Firecracker and gVisor?

Firecracker puts a whole kernel between untrusted code and the host; gVisor puts a reimplementation of the kernel’s interface between them, in a process. A Firecracker VM enforces that boundary in hardware with KVM; gVisor has no guest OS at all.

How gVisor Isolates: a Kernel in Userspace

gVisor is an application kernel that implements a Linux-like interface, written in a memory-safe language, Go, and running in userspace.[3]

Three parts matter. The Sentry is that kernel: it intercepts the sandboxed program’s system calls and answers them itself instead of passing them to the host kernel. The Gofer is a separate host process that mediates all access to filesystem resources, so the Sentry never opens host files. runsc is the entrypoint, and it implements the OCI runtime specification used by Docker and Kubernetes: docker run --runtime=runsc puts a container inside the sandbox,[4] and on Kubernetes a pod selects it with runtimeClassName: gvisor.[5]

How the Sentry catches syscalls is a pluggable platform: systrap uses seccomp’s trap feature, and KVM uses processor virtualization extensions for faster address space switches, still with no virtualized hardware and no guest kernel.[6] The production guide recommends KVM on bare metal and systrap inside a VM.[7]

How Firecracker Isolates: a Kernel per Sandbox

Firecracker boots a real guest kernel on KVM and keeps its device model deliberately small: VirtIO net, block and vsock, a serial console, and little else. Seccomp filters limit the host system calls Firecracker itself may make, and in production it is started through a jailer that sets up cgroups and a chroot, drops privileges, then execs Firecracker unprivileged.[8] The microVM vs container comparison covers why that separate kernel changes the boundary.

Compatibility: What gVisor Does Not Implement

Because the guest runs a real Linux kernel, anything that runs on Linux runs inside a Firecracker microVM. gVisor reimplements the kernel, and its own documentation says it implements only a subset of the Linux syscall ABI.[16] The listed gaps include io_uring, which is disabled by default, and KVM from inside the sandbox. gVisor says the unimplemented part is mostly alternatives to syscalls it does support; code you cannot predict, which is what an LLM writes, is where a missing one becomes a confusing failure.


Which Is More Secure, Firecracker or gVisor?

Firecracker gives the stronger boundary against a kernel exploit; gVisor gives a strong one without a hypervisor. The answer depends on what you are defending against.

gVisor’s threat model is a host kernel bug. It was created to provide additional defense against the exploitation of kernel bugs by untrusted userspace code.[9] Untrusted code talks only to the Sentry, and the Sentry makes a minimal set of host system calls that excludes creating sockets, unless host networking is enabled, and opening files, unless directfs is enabled.

Firecracker’s threat model is that the guest kernel is already gone. A compromised guest kernel is still a guest. The escape has to go through KVM, then the handful of emulated devices, then the jailer.[8]

gVisor does not claim protection against hardware side channels,[9] and Firecracker’s production guide says it cannot mitigate the host’s hardware vulnerabilities, so that falls to how the host is configured.[20] Neither primitive decides what credentials the sandbox holds or what it can reach; the agent sandbox design does.


How Do Firecracker and gVisor Compare in Performance?

Inside a Firecracker guest, system calls are handled by a normal Linux kernel and only device I/O crosses to the host through virtio; gVisor runs CPU work directly but pays on every system call.

Firecracker gVisor
Boundary Separate guest kernel on KVM Userspace kernel (Sentry) in a process
Start Boot under 125 ms; restore from snapshot Process start, no kernel to boot
CPU-bound code Runs on the CPU under KVM No instruction emulation
Syscall-heavy code Handled by the guest kernel Every call traverses the Sentry
File I/O virtio-block to the guest kernel Routed through the Gofer
Network virtio-net Own stack, less CPU efficient
Linux compatibility Real Linux kernel A subset of the syscall ABI
Host requirement KVM and /dev/kvm Any Linux; KVM platform on bare metal

Firecracker and gVisor project documentation: [1] [6] [8] [10] [11] [16]. Checked 2026-09-10 and 2026-10-22.

Cold Start, Warm Pools and Snapshots

Firecracker’s project site gives a boot under 125 ms and under 5 MiB of memory overhead per microVM, which it attributes to its minimal device model and streamlined kernel loading, and up to 150 microVM launches per second per host, with no host hardware stated for that rate.[1] A real deployment rarely pays even the boot: a pool of pre-initialised runtimes is restored from a snapshot. Resuming the same snapshot more than once is considered insecure unless the guest entropy pool and cryptographic tokens are made unique again.[12]

gVisor has no kernel to boot, so its cold start is a process start.

Syscall and I/O Overhead in an Agent Loop

gVisor’s performance guide names the structural cost: application system calls must traverse additional layers of software. CPU instructions run directly, but file operations route through the Gofer and the network stack is less CPU efficient.[10] An agent loop is the wrong shape for that: git clone, npm install and a test suite are thousands of small file and socket operations, and each pays the toll. Inside a Firecracker guest those calls hit a normal kernel.


Firecracker vs gVisor vs Docker: When Are Containers Enough?

A plain container is enough when the code is yours, or the worst case is a mess rather than a breach. The efficiency of a single shared kernel is also the exposure: gVisor’s own framing is that container escape is possible with a single vulnerability.[3] Seccomp narrows what a process can ask the kernel for, but a kernel bug reachable through an allowed syscall is still a host compromise.

If the threat is a prompt-injected agent deleting the repo, a container with scoped credentials and a locked-down network covers most of it. Against someone trying to break out, use a virtual sandbox built on either primitive.


Which Should You Choose for an AI Agent Sandbox?

Choose Firecracker when the code is untrusted or syscall-heavy and you control the hardware; choose gVisor when you are on Kubernetes or inside cloud VMs without usable KVM. AWS Lambda runs on Firecracker,[1] and so does Vercel Sandbox.[13] Google runs gVisor under Cloud Run and GKE Sandbox, and gVisor lists OpenAI and Anthropic among its users for code execution.[2] Modal says each container runs in its own sandbox using primitives like gVisor or microVMs.[14]

Pick Firecracker when:

  • the workload is an agent loop of installs, git operations and tests, where syscall overhead compounds;
  • you cannot predict which syscalls the code will make, so compatibility gaps become outages;
  • you can run on bare metal, or on a provider that does, since Firecracker needs the KVM kernel module and read-write access to /dev/kvm.[11]

Pick gVisor when:

  • your platform is Kubernetes and you want isolation as a runtimeClassName;
  • your hosts are cloud VMs without usable KVM, where systrap runs and Firecracker cannot;
  • the workload is CPU-bound or short-lived and rarely touches the filesystem.

Kata Containers is not a third mechanism: it is a container runtime that runs QEMU, Cloud Hypervisor or Firecracker underneath, the usual path to a microVM boundary inside Kubernetes.[15]


How Do You Safely Run LLM-Generated Python in Production?

Run each job in its own Firecracker microVM or gVisor sandbox, with outbound traffic denied except to named hosts, no secrets inside, and a hard time limit. Each setting below is shown for Docker with gVisor and for a Fly.io Sprite, a Firecracker microVM. The longer walkthrough is in running LLM-generated Python.

Network: Deny by Default, Allow Named Hosts

Injected code that reaches the internet can send your data anywhere. With Docker, attach the sandbox only to a network created with docker network create --internal sandbox-net, which restricts external access,[17] and put on that network a proxy that forwards only to the hosts the job needs. On a Sprite, a network policy with named domain rules does the same job:

{
  "rules": [
    { "domain": "pypi.org", "action": "allow" },
    { "domain": "files.pythonhosted.org", "action": "allow" },
    { "domain": "api.example.com", "action": "allow" }
  ]
}

An allowed domain is a way out as well as a way in, so presets like defaults are a convenience for trusted agents, not a boundary for untrusted code.

Syscall Surface: a Separate Kernel, Fewer Privileges

Under gVisor the code talks to the Sentry; in a Sprite it talks to its own guest kernel, so its syscalls never reach a shared one. Inside either boundary, drop what Python never needs. With Docker and runsc:

docker run --rm --runtime=runsc --network sandbox-net \
  --read-only --tmpfs /tmp \
  --cap-drop ALL --security-opt no-new-privileges=true \
  --memory 512m --pids-limit 128 \
  -v "$PWD/job:/job:ro" python:3.13-slim \
  timeout --kill-after=5s 30s python3 /job/main.py

Those flags give a read-only root filesystem, no Linux capabilities, no privilege gain, and memory and process limits that keep a fork bomb contained.[18]

Secrets: Keep Credentials Outside the Sandbox

Generated code can read and print every environment variable and file it is given, so the model API key stays in the process that calls the model, outside the sandbox. A credential the job needs is a short-lived token the orchestrator mints per job, expiring no later than the job’s deadline. Sprites add connectors: the Sprite calls a provider through the Sprites gateway, which holds the stored credential, so the provider token never enters the Sprite.

Time: a Hard Wall-Clock Limit

GNU timeout runs a command and kills it if it is still running after the interval, and --kill-after follows up with a KILL signal if the first one is ignored.[19] The Sprites exec API takes its own timeout, 30 seconds by default and at most 10 minutes. Set a last limit outside both: destroy the sandbox at the job’s deadline.


Firecracker and gVisor on Fly.io

Fly.io runs every workload in a Firecracker microVM with its own guest kernel. The microVMs run on dedicated physical servers, per the platform architecture docs, and Fly Machines expose them through a REST API.

Sprites are Firecracker microVMs for untrusted and LLM-generated code: each has its own kernel and a persistent filesystem with copy-on-write checkpoints, so you restore the disk after a run breaks it. Outbound traffic is unrestricted until you apply a network policy. Once applied, a request to a domain outside it gets a DNS refusal and raw IP connections are blocked. The policy is set through the Sprites API; code inside the Sprite can read it but cannot rewrite it.


Frequently Asked Questions

Is gVisor a VM?

No. gVisor is an application kernel running in userspace, with no guest operating system and no virtualized hardware. Fly.io does not use gVisor; every Machine and Sprite is a Firecracker microVM with its own guest kernel.

Is gVisor safe?

Yes, for the threat it was built for. gVisor defends against untrusted code exploiting host kernel bugs: the program talks to the Sentry, which makes only a minimal set of host system calls. Fly.io does not use gVisor; it runs untrusted code in Firecracker microVMs instead.

Is Firecracker VM safe?

Yes, for the threat model it was built for. Firecracker runs each workload in a KVM-backed microVM with its own guest kernel, a small device model and a privilege-dropping jailer. Fly.io runs customer code in these microVMs.

What is the main difference between Firecracker and Kata Containers?

Firecracker is a virtual machine monitor; Kata Containers is a container runtime that builds lightweight virtual machines and can use Firecracker, QEMU or Cloud Hypervisor underneath. Fly.io does not use Kata; it drives Firecracker directly and exposes the result as Machines and Sprites.

Does gVisor work with Docker and Kubernetes?

Yes. gVisor installs as a Docker runtime named runsc, so docker run –runtime=runsc puts a container inside the sandbox, and Kubernetes pods select it with runtimeClassName: gvisor. Fly.io boots the container image inside a Firecracker microVM instead, so there is no runtime to swap.

Does Modal use gVisor?

Yes, as one option. Modal says each container runs in its own sandbox, isolated from the host, using primitives like gVisor or microVMs. Fly.io uses one primitive throughout: every Machine and Sprite is a Firecracker microVM with its own guest kernel.

How fast does Firecracker boot?

Firecracker’s project site gives a boot under 125 milliseconds, which it attributes to a minimal device model and streamlined kernel loading. Fly.io runs Machines and Sprites on Firecracker, so each one boots its own guest kernel rather than sharing the host’s.

Does Fly.io wrap my container in gVisor?

No. Fly.io runs each workload in a Firecracker microVM with its own Linux kernel. Sprites add an egress allowlist, applied when you set a network policy, and checkpoints on top of that hardware boundary.


Sources

  1. ^ Firecracker, “Firecracker: Secure and fast microVMs for serverless computing”. firecracker-microvm.github.io. Checked 2026-10-22.
  2. ^ gVisor, “Who’s Using gVisor”. gvisor.dev/users. Checked 2026-09-10.
  3. ^ gVisor, “What is gVisor?”. gvisor.dev/docs. Checked 2026-09-10.
  4. ^ gVisor, “Docker Quick Start”. gvisor.dev/docs/user_guide/quick_start/docker. Checked 2026-09-10.
  5. ^ gVisor, “Kubernetes Quick Start”. gvisor.dev/docs/user_guide/quick_start/kubernetes. Checked 2026-09-10.
  6. ^ gVisor, “Platform Guide”. gvisor.dev/docs/architecture_guide/platforms. Checked 2026-09-10.
  7. ^ gVisor, “Production guide”. gvisor.dev/docs/user_guide/production. Checked 2026-09-10.
  8. ^ Firecracker, “Firecracker Design”. github.com/firecracker-microvm/firecracker/blob/main/docs/design.md. Checked 2026-09-10.
  9. ^ gVisor, “Security Model”. gvisor.dev/docs/architecture_guide/security. Checked 2026-09-10.
  10. ^ gVisor, “Performance Guide”. gvisor.dev/docs/architecture_guide/performance. Checked 2026-09-10.
  11. ^ Firecracker, “Getting Started with Firecracker”. github.com/firecracker-microvm/firecracker/blob/main/docs/getting-started.md. Checked 2026-09-10.
  12. ^ Firecracker, “Firecracker Snapshotting”. github.com/firecracker-microvm/firecracker/blob/main/docs/snapshotting/snapshot-support.md. Checked 2026-09-10.
  13. ^ Vercel, “Vercel Sandbox”. vercel.com/docs/vercel-sandbox. Checked 2026-09-10.
  14. ^ Modal, “Security and privacy at Modal”. modal.com/docs/guide/security. Checked 2026-10-22.
  15. ^ Kata Containers, “Kata Containers: Open Source Container Runtime Software”. katacontainers.io. Checked 2026-09-10.
  16. ^ gVisor, “Applications”. gvisor.dev/docs/user_guide/compatibility. Checked 2026-10-22.
  17. ^ Docker, “docker network create”. docs.docker.com/reference/cli/docker/network/create. Checked 2026-10-22.
  18. ^ Docker, “docker container run”. docs.docker.com/reference/cli/docker/container/run. Checked 2026-10-22.
  19. ^ GNU Coreutils, “timeout: Run a command with a time limit”. gnu.org/software/coreutils/manual/html_node/timeout-invocation.html. Checked 2026-10-22.
  20. ^ Firecracker, “Production Host Setup Recommendations”. github.com/firecracker-microvm/firecracker/blob/main/docs/prod-host-setup.md. Checked 2026-10-22.

Run untrusted code in Sprites

Firecracker microVMs with their own kernel, checkpoints, and an egress allowlist you control.

Sign up