Skip to content
Runtime

nsjail vs Firecracker process jail or microVM for untrusted code?

Runtime Cloud (withruntime.com) gives each sandbox its own kernel. nsjail shares the host's kernel.

Which should you use, nsjail or Firecracker?

It depends on whether you know the code before it runs. For model output and agents with a shell, Runtime runs the Firecracker side as a service: a microVM per sandbox. Pick nsjail for known programs on your own Linux hosts, such as judge systems, CTF services and fuzzing targets. It needs no KVM and starts a process, not a machine. Many setups use both: they jail the monitor and run the code in the VM.

How nsjail works

nsjail is a "Linux process isolation tool using namespaces, resource limits, and seccomp-bpf syscall filters," published in Google's GitHub organization under Apache 2.0. Its README ends: "This is not an official Google product."

It builds a jail out of kernel features:

  • Namespaces: UTS, mount, PID, IPC, network, user, cgroup and time.
  • Filesystem: chroot() or pivot_root(), read-only bind mounts, a custom /proc and tmpfs.
  • Limits: wall time (600 seconds by default), CPU time, address space, open files and process count, plus cgroup v1 or v2 limits on memory, PIDs and CPU.
  • System calls: seccomp-bpf policies written in Kafel, such as ALLOW { read, write, exit, exit_group } DEFAULT KILL.
  • Network: an empty network namespace, a cloned MACVLAN interface, or userland networking through pasta.

It runs a program once, re-runs it in a loop for fuzzing, or listens on a TCP port and jails a fresh process per connection. Its README names CTF challenge hosting, fuzzing and desktop application sandboxing as uses. A typical run:

Terminal./nsjail -Mo --chroot / --user 99999 --group 99999 \  --time_limit 10 --rlimit_as 512 -- /usr/bin/python3 answer.py

Everything inside the jail still runs on the host's kernel. The namespaces change what the process can see. The seccomp policy limits which system calls it can make. The calls it is allowed to make are handled by the same kernel as every other process on the machine.

How Firecracker works

Firecracker is a virtual machine monitor. It asks the host's KVM for a virtual machine and boots a guest Linux kernel in it. The code's system calls go to that guest kernel. What reaches the host is the monitor's small device model, "only 5 emulated devices" in the project's count, and its own filtered system calls.

Firecracker also uses the same tools as nsjail, one level out. Its jailer "sets up system resources that require elevated permissions (e.g., cgroup, chroot), drops privileges, and then exec()s into the Firecracker binary." The monitor then runs with per-thread seccomp filters. The design document assumes "all vCPU threads are considered to be running malicious code as soon as they have been started."

Side by side

nsjail Firecracker
What it is A process jail A virtual machine monitor for microVMs
Kernel the code uses The host's Its own guest kernel
Boundary Namespaces, rlimits, cgroups, seccomp-bpf Hardware virtualization, then a jailer and seccomp on the VMM
Host surface Every system call the policy allows 5 emulated devices, in the project's count, and the VMM's calls
Root inside Root in a user namespace, on the host kernel Root in its own machine
Input A host directory or / as the root filesystem A kernel image and a root filesystem image
Network Empty namespace, MACVLAN or pasta virtio-net; filtering is left to the host
Needs User namespaces enabled, or root KVM on the host
Start time No figure published Up to 125 ms to guest init, in its specification
Memory overhead No figure published Up to 5 MiB for the VMM threads, in its specification
Language, licence C++, Apache 2.0 Rust, Apache 2.0

Is nsjail enough for LLM-generated code?

It narrows the attack surface a great deal, and a tight seccomp policy can make a kernel bug hard to reach. The limit is the one every process jail shares. The code runs on the host kernel, so one exploitable bug in a system call the policy allows reaches the whole machine. General code needs many system calls. A policy loose enough for Python, pip and a compiler leaves much of the kernel reachable.

A microVM moves the boundary. The code can have root and every system call, because a kernel that belongs to a disposable machine answers them. Reaching the host means breaking that kernel and then the monitor.

Firecracker does not do everything for you either. Its design document says it "does not perform any network traffic filtering" and that guest traffic "should be filtered at the host-level." A production service still needs that layer, plus leases, quotas and cleanup.

When each fits

  • Pick nsjail for known programs on your own Linux hosts: judge systems for a fixed compiler and test set, CTF services, fuzzing targets, and sandboxing desktop applications. It needs no KVM and starts a process, not a machine.
  • Pick Firecracker for code you cannot predict: model output, agents with a shell, user-submitted projects that install their own packages, or anything that wants root.
  • Use both as Firecracker itself does: jail the monitor process, and put the untrusted code inside the VM.

Runtime Cloud

Runtime puts each sandbox in its own Firecracker microVM, and runs the host side for you. Network, CPU, memory and cost are enforced on the host.

Runtime operates the host side: a Firecracker microVM per sandbox on dedicated servers, and the network filtering Firecracker leaves to the host. Every outbound connection goes through a proxy on the host. Private and internal addresses are refused, and root in the sandbox cannot change the rules (security).

TypeScriptimport { Sandbox } from "withruntime";const code = "import os; print(os.getuid(), os.uname().release)"; // what the model wroteawait using sbx = await Sandbox.create({  network: { internet: false },  timeoutSeconds: 120,  onLeaseEnd: "stop",});await sbx.files.write("/workspace/answer.py", code);const run = await sbx.exec(["sudo", "python3", "answer.py"], { timeoutMs: 10_000 });console.log(run.exitCode, run.timedOut, run.stdout); // root, in its own kernel
Pythonfrom withruntime import Sandboxcode = "import os; print(os.getuid(), os.uname().release)"  # what the model wrotewith Sandbox.create(    network={"internet": False},    timeout_seconds=120,    on_lease_end="stop",) as sbx:    sbx.files.write("/workspace/answer.py", code)    run = sbx.exec(["sudo", "python3", "answer.py"], timeout_ms=10_000)    print(run.exit_code, run.timed_out, run.stdout)  # root, in its own kernel

The command timeout and the network switch do the work of nsjail's --time_limit and empty network namespace. The network rules and the lease are enforced on the host, outside the guest.

More: run untrusted LLM code, grade student code, what is egress control?, Firecracker vs gVisor.

A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card:

Terminalnpx withruntime sandboxes run -- sudo id

To run your own untrusted code this way, sign in with npx withruntime login and use the free usage. Code already on another sandbox moves with the migration guide.

Sources

Checked 26 October 2026.

Facts on this page were checked on 26 October 2026.

Keep comparing.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card