Firecracker Escape: From Guest to Host Root
pwn.ai’s Paulos Yibelo has published the second half of PwnEscape: a chain that starts with a Linux IPv4 checksum bug, uses the resulting host-memory primitive to find a live Firecracker vCPU thread, and rewrites its saved registers so the VMM calls write(2) as root on the host. The VM stays up. The marker appears on Firecracker’s stderr. The caveat is as important as the exploit: the target Firecracker ran without the jailer and as root.
Key Takeaways:
- pwn.ai chained CVE-2026-99999, a Critical Linux kernel IPv4 checksum bug, into a Firecracker vCPU thread and made the VMM execute a host
write(2)call as root.- The proof used Firecracker v1.16.1 on x86-64, host kernel
7.0.0-1011-aws, and guest kernel6.18.44+. Firecracker was launched directly as root undersystemd-run, pinned withtaskset, and had no jailer.- The root result is a consequence of that deployment. Firecracker’s production containment includes privilege dropping, namespaces, and seccomp; the writeup says a jailed deployment needs a separate assessment.
- The bug is in the Linux kernel’s networking stack, not in Firecracker. The upstream fix is
6785011f8b16, which guards checksum completion against writing into an already-parsed IPv4 header.- pwn.ai explicitly does not claim root command execution in any vendor’s production environment. This was an owned lab target, and the proof is a controlled marker write to stderr; an interactive root shell was outside the proof.
Firecracker is the microVM monitor behind services such as AWS Lambda and Fargate, and it is a common building block for multi-tenant sandboxes. That makes a guest-to-host chain worth reading carefully. It also makes the deployment details worth reading before the headline. Exposure is deployment-dependent. A microVM boundary can fail when the host kernel hands a guest-controlled value to a later consumer, and when the VMM is running with more privilege than it needs.
What pwn.ai Actually Broke
The second part of PwnEscape does not exploit a bug in Firecracker’s code. It takes the host-memory primitive from Part 1 and points it at the process running the VM. Part 1 came out of Vercel’s $1 million Sandbox challenge. It found a Linux networking flaw that let a guest-controlled checksum hint rewrite an IPv4 header after the kernel had validated it. The result was a repeatable 32-byte host-memory disclosure, and in an owned KVM fixture, selected 64-byte host-kernel writes. Four separate cold boots completed a host-root helper chain.
Part 2 is the Firecracker-specific pivot. The researchers used the host-memory access to locate a guest page on the host, recover the Firecracker process’s page tables, find the binary under ASLR, and identify the saved register frame of the thread sitting in KVM_RUN. Then they changed that frame’s return path.
| Fact | Recorded detail |
|---|---|
| Target VMM | Firecracker v1.16.1, x86-64 |
| Host kernel | 7.0.0-1011-aws |
| Guest kernel | 6.18.44+ |
| VMM privilege | root, launched under systemd-run and pinned with taskset |
| Jailer | not used |
| Underlying bug | CVE-2026-99999, Linux IPv4 checksum metadata, CVSS 9.3 |
| Host proof | Firecracker wrote N8V23M2\n to stderr; process stayed alive; guest SSH stayed responsive |
The Bug Under the Chain: CVE-2026-99999
The root cause is a trust inversion in Linux checksum offload. A packet can travel with CHECKSUM_PARTIAL, meaning the transport checksum is still pending. The sk_buff carries csum_start and csum_offset, which together authorize a later write into packet memory. That is normal, documented behavior. It becomes dangerous when a less-trusted source can influence those values and a later consumer uses a header interpretation that changed after the first validation.
The NVD entry describes the kernel fix as validating checksum_start before completing the checksum. In the tested path, a guest-controlled checksum hint caused skb_checksum_help() to write into bytes that had already been parsed as an IPv4 header. The first byte of the header could change from 0x45 (IPv4, 20-byte header) to 0x4f (IPv4, 60-byte header) without changing the version nibble. A later fragmenter then read the new length and copied 60 bytes from a buffer whose logical linear data was only 28 bytes. The extra 32 bytes were host memory, emitted as apparent IP options in the outgoing packet.
That is the disclosure primitive. The write primitive is the next step: with host memory visible and allocator behavior controlled, the researchers showed selected 64-byte host-kernel writes in their own KVM fixture. Part 2 uses that capability to modify the Firecracker thread. The Linux kernel fix is narrow by design. It adds ip_check_csum_start() before checksum completion in the affected IPv4 consumers, enforcing that the checksum start is at or after the network header plus the parsed IPv4 header length. The accepted commit is 6785011f8b16, merged into mainline on October 14, 2026. The commit message calls the guard a defense-in-depth measure and says broader ingress validation still needs work.
From a Guest Page to the vCPU Thread
The Firecracker part is an address-discovery problem followed by a control-flow problem. Firecracker runs each virtual CPU as a host thread. That thread enters KVM to run the guest and returns to userspace when an event needs handling. The call looks like this:
ioctl(vcpu_fd, KVM_RUN, 0);
While the thread is inside that system call, the host kernel holds its saved userspace registers in a pt_regs structure. The instruction pointer says where execution will resume; the stack pointer says which userspace stack it will use. If a guest can find and modify that frame, it can choose what Firecracker does when the thread returns from KVM_RUN.
The chain has four resolvers:
- Guest page to host physical address. The guest puts a nonce in a page and searches candidate EPT roots until a translation lands on a page containing that nonce. This connects a guest physical address to a host physical address.
- Host physical address to a host address space. A reverse walk of the host page tables finds which process maps that page. The check runs in both directions: translate the recovered virtual address back and confirm it resolves to the same physical page and nonce.
- Address space to the Firecracker image. The mapper finds the ELF image and a known byte sequence in Firecracker’s
write(2)wrapper, then recovers the load bias so it can compute runtime addresses under ASLR. - Image to the live vCPU frame. The frame finder searches host memory for a
pt_regsthat matches an activeKVM_RUN: syscall identity and in-progress state, theKVM_RUNrequest, a plausible file descriptor, the validated ioctl continuation, a stack pointer that translates through the recovered page tables, valid user segment selectors and flags, and a caller return address inside the Firecracker text mapping.
The search left one candidate. The helper then repeated the code signature, frame, and stack checks before changing anything. That matters because a match on a stale stack frame would produce a convincing but wrong target.
The payload was deliberately small. The researchers made Firecracker call its own write(2) wrapper with a marker string on its private userspace stack:
RIP = address of Firecracker's write wrapper
RDI = 2 // stderr
RSI = virtual address of "N8V23M2\n" on Firecracker's stack
RDX = 8
RSP = virtual address of the temporary return sequence
A successful write returns 8, while a successful KVM_RUN returns 0. The temporary return sequence therefore starts with a xor eax,eax; ret gadget, then returns to Firecracker’s original ioctl continuation. The control flow is:
KVM_RUN returns to userspace
-> Firecracker's write wrapper emits the marker
-> xor eax,eax; ret sets the return value to zero
-> execution resumes at the original ioctl continuation
The guest triggers the return by writing one byte to its serial port. The kernel restores the modified registers, Firecracker runs the write, the return sequence clears eax, and the thread rejoins its normal path. The helper then restores the three stack words it changed. The writeup records one copy of the marker, eight bytes including the newline, no shell attempt, no host command attempt, and no modification to Firecracker’s text or shared libraries.
Why the Host Call Ran as Root
This is the part that turns a VMM compromise into host root: Firecracker was running as root. The target details are explicit. Firecracker was launched directly as root under systemd-run and pinned with taskset. Consequently, the call Firecracker executed ran with root privileges on the host. The configuration had no jailer.
Firecracker’s production containment is a separate layer. The design documentation describes dropping privileges and restricting the process with namespaces and seccomp. The jailer is the component that sets up that confinement. A deployment using those controls needs a separate assessment of the privileges and resources available after compromising its VMM. That is the correct reading: the chain shows control of the VMM thread, and the root outcome depends on how the VMM was deployed.
That distinction is not a footnote. A VMM that runs as an unprivileged user inside a jail, with a seccomp filter and a restricted filesystem view, presents a much smaller post-compromise surface than a VMM running as root with no jailer. The writeup leaves open whether the jailer would have stopped the register rewrite. The root execution result belongs to the tested deployment, and a jailed deployment needs its own evaluation.
What the Proof Shows, and What It Does Not
It shows that a guest can use a host-kernel memory primitive to find a live Firecracker vCPU thread and redirect its return from KVM_RUN. The host call is observable on Firecracker’s stderr, the guest remains healthy, and the changed stack state is restored. That is a complete control-flow proof against the tested VMM.
It does not show that every Firecracker deployment is vulnerable in the same way. The chain depends on the CVE-2026-99999 primitive, a specific Firecracker build, and a VMM that was running as root without the jailer. The result is a lab-only proof of concept. Production environments were outside its scope.
The defect is in the Linux kernel. CVE-2026-99999 is an IPv4 checksum bug; Firecracker is the target that the primitive was pointed at.
The fix belongs in the host kernel, and the containment question belongs to the Firecracker deployment.
The proof is a controlled write(2) call. Extending it to other calls would require code and arguments compatible with the process’s mappings and syscall policy. The marker is evidence of code execution; an interactive session was outside the proof.
The Fix: Patch the Host Kernel, Contain the VMM
The immediate fix is the upstream Linux patch. The accepted commit is 6785011f8b16; distributions and cloud providers are backporting it. If you run Firecracker, KVM, or any multi-tenant microVM stack, check the host kernel, not just the guest image. The guest kernel version does not fix a host networking bug.
The second fix is deployment hygiene. Run Firecracker with the jailer. Drop privileges. Use namespaces and seccomp. Do not run the VMM as root unless you have a specific reason and have measured the post-compromise surface. The target did not have those controls, and that is why the marker ran as root.
The broader lesson is about deferred metadata. The kernel validated one representation of the packet, then a later operation changed a field that another consumer trusted. The same pattern can appear anywhere a guest-controlled value authorizes a write that happens after parsing. The upstream fix guards the IPv4 header boundary; it does not prove that every protocol-specific checksum destination is correct. If you build sandboxes, test the host networking path with the same suspicion you apply to the hypervisor.
Bottom Line
The headline is accurate in the narrow sense: pwn.ai escaped a Firecracker microVM and got root-level code execution on the host. The qualifier is what makes the story useful: the VMM was running as root, without its jailer, and the underlying bug was in the Linux kernel’s networking stack. Patch the host kernel, run Firecracker with its containment layer, and treat the microVM boundary as a stack of assumptions rather than a single wall.
Sources and References
- pwn.ai: Firecracker VM Escape: PwnEscape Part 2
- pwn.ai: PwnEscape: Guest-to-Host KVM Escape (CVE-2026-99999)
- NVD: CVE-2026-99999
- Linux commit 6785011f8b16: ipv4: validate checksum_start before completing checksum
- Firecracker design: sandboxing and containment
- Firecracker jailer documentation
- Vercel: Findings from the $1M Sandbox challenge
