Skip to content
Guides · Sandboxes and isolation

gVisor vs Kata Containers vs Firecracker for Untrusted Code

Updated October 31, 2026 .md

Short answer: Pick by boundary and by what the code needs. gVisor puts a user-space kernel in front of the host, needs no KVM, but implements only part of Linux. Kata Containers runs each Kubernetes pod in its own VM. Firecracker is a minimal microVM monitor you build your own platform around.

Sources: each project's own docs and repository, linked inline and read on the date above. Sandboxer runs none of the three: each Sandboxer sandbox is a Cloud Hypervisor microVM. The probes further down ran in one of those.

If you're still choosing between a plain container and a VM, start with Container vs microVM. This page compares three open-source projects used for the next step.

They aren't the same kind of thing#

  • gVisor is an OCI runtime (runsc) with an "application kernel" written in Go that "runs in userspace". It intercepts the application's system calls and "acts as the guest kernel, without the need for translation through virtualized hardware". Its docs say it is "not a VM in the everyday sense of the term". (What is gVisor?)
  • Kata Containers is an OCI runtime that starts a lightweight VM with its own guest kernel and runs your container inside it. "Kata Containers represents a Kubelet pod as a VM." It drives a hypervisor you choose: QEMU, Cloud Hypervisor, Firecracker, Dragonball or StratoVirt. (Kubernetes support, hypervisors)
  • Firecracker is a virtual machine monitor that "uses the Linux Kernel Virtual Machine (KVM) to create and run microVMs". It is not a container runtime on its own; its FAQ points to Kata Containers and firecracker-containerd for that. (README, FAQ)

So Kata and Firecracker can be the same stack: Kata is one way to run containers on Firecracker.

Side by side#

gVisor Kata Containers Firecracker
Isolation boundary User-space kernel (the Sentry) between the app and the host kernel A VM per pod, with its own guest kernel A microVM per workload, with its own guest kernel
Who handles a syscall The Sentry's own implementation The guest Linux kernel The guest Linux kernel
Linux compatibility "Only implements a subset of the Linux syscall ABI" A real guest kernel; runtime-level gaps are listed in Limitations A real guest kernel; Linux and OSv guests
Needs KVM on the host No. The systrap platform suits "a machine without virtualization support" Yes: "requires nested virtualization or bare metal" Yes: "requires read/write access to /dev/kvm"
Kubernetes RuntimeClass gvisor, via the containerd shim RuntimeClass kata; "officially supported CRI-O and containerd runtime" Through Kata or firecracker-containerd
Unit you manage A container A pod (one VM, one or more containers) A VM: you supply the kernel, rootfs, TAP networking and jailer

Sources: gVisor compatibility, gVisor platforms, gVisor on Kubernetes, Kata install, Kata with containerd and Kubernetes, Firecracker getting started, Firecracker design.

What each boundary is trusted to stop#

  • gVisor "was created in order to provide additional defense against the exploitation of kernel bugs by untrusted userspace code". It also says it "relies on the host operating system and the platform for defense against hardware-based attacks", and on host cgroups against resource exhaustion. (security model)
  • Kata Containers "runs in a dedicated kernel, providing isolation of network, I/O and memory and can utilize hardware-enforced isolation with virtualization VT extensions". Inside the VM, the guest kernel still sets up namespaces and cgroups around the container. (katacontainers.io, architecture)
  • Firecracker names "the Linux KVM and the Firecracker virtualization boundary" as the first layer. For defense in depth it should run under seccomp filters (installed automatically), cgroups and namespaces, and "should be started only via the jailer binary" in production. (design)

What runs inside#

This is where the choice usually gets made. Untrusted code from users or agents often wants more than a language runtime: Docker, a mounted disk image, a profiler, sometimes a VM of its own.

Inside the sandbox gVisor, per its docs Kata Containers, per its docs Firecracker, per its docs
Docker Supported, with runsc flags such as --net-raw (and --allow-packet-socket-write for Docker 28+, which "allows sandboxed code to craft arbitrary network packets"); dockerd runs with iptables off, so docker run --expose doesn't publish ports Not covered in the docs we read; privileged containers get "elevated capabilities within the guest", and passing host devices to them must be turned off Whatever your guest image contains
KVM / nested VMs "Usage of KVM from within the sandbox is not supported" Not covered in the docs we read Not covered in the docs we read
io_uring "Disabled by default"; when on, "limited to basic I/O operations" Guest kernel's behavior Guest kernel's behavior
perf_event_open Unimplemented: "No support for perf counters" Guest kernel's behavior Guest kernel's behavior
Mount ext4 from a block device Not supported inside the sandbox Guest kernel's behavior Guest kernel's behavior
systemd Not covered in the docs we read The workload is a container inside the guest; not covered in the docs we read Your guest image's init

Sources: Docker in gVisor, gVisor compatibility, gVisor syscall table, Kata limitations.

gVisor's docs add a fair point: most language runtimes probe for io_uring and fall back to other I/O calls, so "most programs" in Python, Java, Node.js, PHP and Go work. The gaps matter when the code is a whole toolchain rather than a script.

What a full VM gives the code: a real test#

We ran these in one Sandboxer default sandbox (Cloud Hypervisor microVM, 4 vCPU, 8 GB). This shows what a guest with its own Linux kernel allows. We did not run gVisor, Kata or Firecracker for this page, so the table above, not this test, is the source for their behavior.

sbx new --name aeo-gvkfc-1 --type default
sbx exec sb_gyfatjok6o "uname -r"
sbx exec sb_gyfatjok6o "systemd-detect-virt; ps -p 1 -o comm="
sbx exec sb_gyfatjok6o "ls -l /dev/kvm; grep -c -E 'vmx|svm' /proc/cpuinfo"
6.18.56-sandboxer
kvm
systemd
crw-rw---- 1 root kvm 10, 232 Oct 31 11:00 /dev/kvm
4

Its own kernel build, KVM virtualization, systemd as PID 1, and /dev/kvm with vmx/svm on all 4 vCPUs.

Syscall probe. A short Python script (probe.py, listed below) calls io_uring_setup, perf_event_open (a software CPU-clock counter) and the KVM ioctls KVM_GET_API_VERSION and KVM_CREATE_VM directly:

sbx scp ./probe.py sb_gyfatjok6o:/home/user/
sbx exec sb_gyfatjok6o "python3 probe.py"
sbx exec sb_gyfatjok6o "sudo python3 probe.py"
io_uring_setup: ok (fd 3)
perf_event_open: failed: EACCES
KVM_GET_API_VERSION: 12
KVM_CREATE_VM: ok (vm fd)

io_uring_setup: ok (fd 3)
perf_event_open: ok (fd 3)
KVM_GET_API_VERSION: 12
KVM_CREATE_VM: ok (vm fd)

The first perf_event_open failure was the guest kernel's own policy, not a missing syscall:

sbx exec sb_gyfatjok6o "cat /proc/sys/kernel/perf_event_paranoid /proc/sys/kernel/io_uring_disabled"
2
0

With perf_event_paranoid at 2, an unprivileged user can't count kernel time. A copy of the script with exclude_kernel and exclude_hv set printed perf_event_open (user-space only): ok (fd 3) as user. With sudo, the original succeeded as written.

Docker with a published port.

sbx exec sb_gyfatjok6o --timeout 120 "docker --version && docker run --rm alpine uname -r"
sbx exec sb_gyfatjok6o --timeout 120 "bash dockerp.sh"   # docker run -d -p 8080:80 nginx:alpine, curl it, show the NAT rule
Docker version 29.9.0, build f415da8
6.18.56-sandboxer
…
200
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80

Docker is preinstalled. The container reports the sandbox's kernel, and -p published the port through the normal iptables DNAT rule.

A systemd unit and an ext4 loop mount.

sbx exec sb_gyfatjok6o "bash unit.sh"   # writes hello-web.service, then systemctl enable --now
sbx exec sb_gyfatjok6o "bash loop.sh"   # mkfs.ext4 on a 256 MB file, mount -o loop
active
200
/dev/loop0 ext4

Then we deleted the sandbox (sbx delete sb_gyfatjok6o --yes). sbx info returned Sandbox not found.

The probe script#

import ctypes, os, fcntl, errno
libc = ctypes.CDLL(None, use_errno=True)
libc.syscall.restype = ctypes.c_long
def report(name, r):
    e = ctypes.get_errno()
    print(f"{name}: " + (f"ok (fd {r})" if r >= 0 else f"failed: {errno.errorcode.get(e, e)}"))
    if r >= 0: os.close(r)
params = (ctypes.c_char * 120)()
report("io_uring_setup", libc.syscall(425, 8, params))          # x86_64
attr = (ctypes.c_uint8 * 128)()
ctypes.c_uint32.from_buffer(attr, 0).value = 1                  # PERF_TYPE_SOFTWARE
ctypes.c_uint32.from_buffer(attr, 4).value = 128                # attr size
ctypes.c_uint64.from_buffer(attr, 8).value = 0                  # PERF_COUNT_SW_CPU_CLOCK
report("perf_event_open", libc.syscall(298, attr, 0, -1, -1, 0))
fd = os.open("/dev/kvm", os.O_RDWR)
print("KVM_GET_API_VERSION:", fcntl.ioctl(fd, 0xAE00))
vm = fcntl.ioctl(fd, 0xAE01, 0)
print("KVM_CREATE_VM: ok (vm fd)" if vm >= 0 else "KVM_CREATE_VM failed")

Run the same script inside whatever runtime you're evaluating. It's a quick way to see which of these calls your candidate allows.

Startup and density, in the projects' own words#

None of this was measured by us.

  • gVisor: it "does not introduce large fixed overheads" and keeps "a process-like model with respect to resource utilization". In its memory test, "the sandbox itself is responsible for a small, mostly fixed amount of memory overhead". It also lists the costs: system calls "must traverse additional layers of software", and its network stack "is less CPU efficient". (What is gVisor?, performance guide)
  • Kata Containers: "Delivers consistent performance as standard Linux containers; increased isolation without the performance tax of standard virtual machines." The site gives no startup figure. (katacontainers.io)
  • Firecracker: its specification, enforced by integration tests on its reference hosts, says it takes "≤ 125 ms" from the InstanceStart API call to the guest's /sbin/init with a minimal kernel and rootfs. VMM memory overhead is "≤ 5 MiB" for a 1 vCPU, 128 MiB microVM. Its design doc cites "a steady mutation rate of 5 microVMs per host core per second". (SPECIFICATION, design)

These are the projects' own claims, made under different conditions, so don't compare them number for number.

Decision table#

Your situation Fits best Why, per the docs
Kubernetes nodes are VMs without nested virtualization gVisor systrap needs no virtualization support; Kata needs bare metal or nested virtualization
Untrusted scripts in Python, Node.js, Go, Java or PHP, high density gVisor Small, mostly fixed overhead per sandbox; language runtimes are regression-tested
Code needs io_uring, perf counters, block-device mounts or KVM Kata or Firecracker gVisor disables, leaves unimplemented or doesn't support each of these
Per-pod VM isolation without leaving Kubernetes Kata Containers RuntimeClass kata on CRI-O or containerd; choose the hypervisor per runtime class
GPU or confidential-computing pods in VMs Kata with QEMU Kata's hypervisor table marks QEMU as the GPU and TDX/SEV-SNP option
You're building your own sandbox or functions platform Firecracker A minimal VMM with an API; you own the kernel, rootfs, networking and jailer
You want containers on Firecracker without writing the glue Kata with Firecracker, or firecracker-containerd Kata needs a block-device snapshotter (devmapper) for Firecracker
Untrusted code runs Docker, systemd and nested VMs, and you don't run nodes A hosted full-VM sandbox See the test above, and Docker and nested KVM in a sandbox

The Kata/Firecracker snapshotter note comes from Kata with Firecracker. For Firecracker against Cloud Hypervisor as the VMM, see Firecracker vs Cloud Hypervisor.

Whatever you pick, the boundary is one layer. Secrets, outbound network and what you do with the output are still yours to handle; Best ways to run untrusted code safely covers those rules.

FAQ#

Is gVisor a virtual machine?#

No, by its own description. It's a user-space application kernel that intercepts system calls. It can use KVM on bare metal to speed up address-space switches, but there's no virtualized hardware and no guest Linux kernel.

Can I run gVisor inside a cloud VM?#

Yes. Its docs say systrap, the default platform, is "a better choice when running inside a VM", and that gVisor "works well when running within a KVM-based virtual machine". Kata Containers needs bare metal or nested virtualization instead.

Do Kata Containers and Firecracker compete?#

Not really. Kata is a container runtime and Firecracker is one of the hypervisors it can drive. Kata also supports QEMU, Cloud Hypervisor, Dragonball and StratoVirt.

Can untrusted code run Docker under gVisor?#

Yes, per the gVisor docs, with extra runsc flags and dockerd started with iptables off. One flag, --allow-packet-socket-write, lets sandboxed code craft arbitrary network packets, so weigh that for multi-tenant use.

What does Sandboxer use?#

Each Sandboxer sandbox is a separate Cloud Hypervisor microVM with its own kernel, so there's no shared kernel between sandboxes. /dev/kvm is available inside, and Docker and systemd come preinstalled.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide