# nsjail vs Firecracker: process jail or microVM for untrusted code? nsjail confines a process on the host kernel with namespaces, limits and seccomp; Firecracker gives code its own kernel in a KVM microVM. **Runtime puts each sandbox in its own Firecracker microVM, and runs the host side for you.** A new sandbox ran its first Python command 351 ms after the create request at the median, over the public internet, on 24 September 2026 ([speed](/docs/speed)), with network, CPU, memory and cost enforced on the host. ## 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: ```bash no-run ./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 narrows which system calls it can make; the calls it is allowed are handled by the same kernel as every other process on the machine. ## How Firecracker works Firecracker is a virtual machine monitor that 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 layer 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, so 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 they are answered by a kernel that belongs to a disposable machine. 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. ## What Runtime runs for you 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](/docs/security#network-access)). ```ts import { Sandbox } from "withruntime"; const code = "import os; print(os.getuid(), os.uname().release)"; // what the model wrote await 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 ``` ```python from withruntime import Sandbox code = "import os; print(os.getuid(), os.uname().release)" # what the model wrote with 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. New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- sudo id ``` More: [run untrusted LLM code](/use-cases/run-untrusted-llm-code), [grade student code](/use-cases/grade-student-code), [what is egress control?](/glossary/egress-control), [Firecracker vs gVisor](/compare/firecracker-vs-gvisor). ## Sources Checked 25 September 2026. - [nsjail README](https://github.com/google/nsjail), [licence](https://github.com/google/nsjail/blob/master/LICENSE) - [Firecracker](https://firecracker-microvm.github.io/), [README](https://github.com/firecracker-microvm/firecracker), [specification](https://github.com/firecracker-microvm/firecracker/blob/main/SPECIFICATION.md), [design](https://github.com/firecracker-microvm/firecracker/blob/main/docs/design.md) Facts on this page were checked on 25 September 2026.