Get in touch
Gabs
Blog

Is a microVM enough to sandbox your coding agent?

No. A Firecracker escape went through a host kernel bug, fixed 8 October, and a VMM run without its jailer. Patch the host and jail it.

Gabriel EspinheiraSenior Full-Stack Engineer
  • Published
  • 8 minReading time
  • EngineeringCategory

Listen to this post· AI-narrated

0:00 / 10:01

On 6 November, PWN Research published code that starts inside a Firecracker microVM and ends up running as root on the host. If you run a coding agent in a microVM, that's the sandbox you're relying on: each agent gets its own guest kernel, and the guest kernel stops the code. The escape went around it. It came in through the host's own Linux networking code, then took over a Firecracker process that ran as root without its jailer. So the answer is no, a microVM isn't enough by itself. How far an escape gets depends on three walls behind it, and you can check them this week.

TL;DR: A microVM alone won't contain your coding agent's code. The Firecracker escape went around it through a host kernel bug, fixed in October, and took over a Firecracker process running as root without its jailer. Patch the host kernel, run the jailer, and make the host trust nothing the guest sends or reports.

How did code escape a Firecracker microVM?

The Firecracker escape took two bugs in a row: a Linux kernel flaw that leaks host memory, then an attack on the Firecracker process itself. Part 1 of PwnEscape, found during Vercel's $1M Sandbox challenge, showed that packets sent from inside a guest could carry checksum metadata the host trusted too late. The host's IPv4 code validated a header and then let a pending checksum write rewrite it, which leaked 32 bytes of host memory per packet (PWN Research (opens in a new tab)). In their own KVM lab they turned that into selected 64-byte writes into host kernel memory, and used those to run a helper as root.

Part 2, published on 6 November, started from that same host-memory access and took a second route, from inside a Firecracker v1.16.1 guest. It found the Firecracker process in host memory, rewrote a saved register frame and made Firecracker run a call of the guest's choosing (PWN Research (opens in a new tab)). Firecracker had been launched directly as root under systemd-run, with no jailer, so that call ran as root on the host.

Vercel says the memory leak was shown against its production sandboxes, while the host crash and code execution ran on the researcher's own KVM and Firecracker machines set up like Vercel's (Vercel (opens in a new tab)). Nobody has shown root on a production sandbox.

Why doesn't the microVM's own kernel protect the host?

A microVM's guest kernel only protects the host from code that has to go through it. This bug sat in the host kernel, in the networking path that handles packets the guest sends through virtio-net and a TAP device. "A microVM gives each agent its own kernel" is how people on r/LocalLLaMA (opens in a new tab) sell it against containers, and it's true. Every packet still lands on the host's kernel, though, and that kernel is shared by every tenant on the machine.

That's also why updating the guest does nothing here. AWS's bulletin 2026-137-AWS says its managed EC2, Lambda and Fargate aren't affected, while self-managed KVM hosts, Firecracker included, are affected until the host kernel is updated and rebooted, with no workaround in between.

The bug is CVE-2026-99999 (opens in a new tab), rated 9.3 in NVD. The upstream fix, commit 6785011f8b16 (opens in a new tab), was merged on 8 October: 44 lines added, 12 removed, across 6 files. The fixed stable kernels are 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.57 and 7.2.11, and distributions number their packages differently, so check your distro's advisory. The patch closes this primitive, which both routes to root needed. Its own message calls it "a defence in depth measure" and says "a more complete validation at input is forthcoming, but needs more work," so expect a second kernel update for the same path.

What does the Firecracker jailer change?

The Firecracker jailer decides what a hijacked Firecracker process is worth. It copies Firecracker into a chroot, moves it into new namespaces and cgroups, drops it to an unprivileged user and group, and only then starts it. Firecracker's production guide says deployments "should be started using the jailer binary", keeps its default seccomp filters at their most restrictive, and advises against --no-seccomp (Firecracker (opens in a new tab)).

The jailer wouldn't have stopped the kernel bug. Part 1 reached root in the researchers' lab with kernel writes alone, and a guest that can write host kernel memory isn't held by a chroot. What the jailer takes away is the shortcut Part 2 used: with it, a guest that takes over Firecracker lands as an unprivileged user behind a syscall filter. The researchers say a jailed setup "requires a separate assessment" of what that process can still reach.

I'd read the jailer as the wall that's cheapest to have up before the next bug. Plenty of tutorials start Firecracker by hand because the jailer adds paths, users and cgroups to set up. On a laptop that's fine. On a host running code your agent wrote from a stranger's prompt, the next VMM bug lands either in a jail or in a root process, and you choose which today.

What should a sandbox trust from inside the microVM?

Everything inside the microVM is attacker input, including every answer the guest gives your control plane. The kernel bug was the challenge's one Critical, among 1,285 reports that earned $242,000 in bounties between them, but Vercel's favourite finding came from that same rule, broken in a different layer (Vercel (opens in a new tab)). When a sandbox saved a snapshot, the host recorded the storage location the guest reported. A researcher rewrote that answer inside two sandboxes they owned and swapped the snapshots, so restoring one account's snapshot brought back the other account's files.

Trail of Bits reviewed the platform for Vercel and boiled it down to three rules, which Vercel says it implemented: eliminate all trust in the guest, give each policy one component that decides it, and assume the next zero day. That last one is the practical list: keep host and guest kernels updated, cut the kernel's attack surface, disable nested virtualization and run the jailer.

Network egress is the same rule applied to packets. Firecracker's docs say it "does not perform any network traffic filtering": a guest's packets go straight to the host's TAP device. Whatever stops your agent from reaching your cloud metadata endpoint or your internal services has to be a firewall rule on the host, which you write.

How do you check a self-hosted microVM sandbox?

A few read-only commands cover the host kernel, the jailer and egress. The control plane needs a code review, because no command shows what your services believe:

# Wall 1: the host kernel. Compare with your distro's advisory for CVE-2026-99999.
uname -r
# Part of the same wall: nested virtualization, which Trail of Bits recommends disabling (kvm_amd on AMD hosts).
cat /sys/module/kvm_intel/parameters/nested
# Wall 2: the jailer. Firecracker should run as an unprivileged user, inside the jailer's chroot, with seccomp on.
for pid in $(pgrep -x firecracker); do
  grep -E '^(Uid|Seccomp):' /proc/$pid/status
  sudo readlink /proc/$pid/root
done
# Wall 3: what the guest can reach. Find the rules that mention the metadata address.
sudo nft list ruleset | grep -n 169.254.169.254
# On hosts still on iptables-legacy:
sudo iptables -S | grep 169.254.169.254

Read the output this way:

  • uname -r at or above your distro's fixed package, with the host rebooted into it, and nested showing N or 0 unless something on the host needs it.
  • Uid: with a first number other than 0, and Seccomp: showing 2, which is filter mode.
  • A root under the jailer's chroot base, /srv/jailer by default, instead of /.
  • A drop rule for 169.254.169.254 on the guests' TAP interfaces, the example Firecracker's docs give. A rule that matches the address but accepts it, or sits on another interface, doesn't count. Run the same grep for the internal ranges your agents shouldn't reach.

What should you ask a hosted sandbox provider?

Those commands need the host, and a hosted provider keeps the host, so put the same three walls to them as questions. Have your hosts been rebooted into a kernel with the fix for CVE-2026-99999, and when? Is every Firecracker process on a shared host started through the jailer? Does anything your control plane does depend on a value the guest reports, like a snapshot location or an exit status? A provider that answers the first two with dates and versions, and the third with a design rule, has thought about the walls you can't see.

Besides Vercel's report, AWS's bulletin is the provider statement I found, and it says no customer action is needed on AWS's managed services. That's still AWS's word. Anything that runs your agent's code in a microVM, whether you built it or pay for it, deserves the three questions this week.

What to do this week

Start with the kernel, because it closes the primitive both routes to root needed, and plan for the follow-up patch the commit message promises. Then make the jailer non-negotiable on any host that runs agent code, so the next VMM bug lands in a jail. Then read your control plane for every value it takes from the guest, and write the egress rules Firecracker leaves to you. If you rent sandboxes, send the three questions and keep the answers next to the bill. I didn't rerun the escape; the sources are linked where I use them.

I write about building with coding agents and the stack under them on the gabs.app blog. I'm a full-stack engineer and my work is on gabs.app; if you're hiring, the contact form comes straight to me.