{"slug": "9-3-to-root-in-5-hops-i-audited-the-firecracker-escape", "title": "9.3 to root in 5 hops: I audited the Firecracker escape", "summary": "An independent researcher audited the reported Firecracker guest-to-host escape chain, verifying four of five links against primary sources including CVE-2026-99999 (CVSS 9.3), the 44-line kernel fix commit 6785011f8b16 by Michael S. Tsirkin, and the Firecracker v1.16.1 source. The flaw, found by Paulos Yibelo of Pwn.ai during Vercel's $1 million sandbox challenge, lets crafted virtio-net checksum metadata corrupt the IPv4 stack via skb_checksum_help and ultimately reach root code execution on self-managed KVM hosts, while AWS says its managed EC2, Lambda and Fargate are unaffected. The audit confirms the EPT walk, reverse page-table lookup, pt_regs frame discovery and KVM_RUN return path, with the fifth link remaining the open question.", "body_md": "A 9.3-rated kernel flaw plus five chain links turned a guest network packet into root code execution on the host. I did not re-run the escape — my sandbox has no `/dev/kvm`, and reproducing a guest-to-host exploit is not a thing you do casually. So I audited every link in the chain against primary sources instead: the CVE record, the kernel fix commit, the Firecracker v1.16.1 source, and the kernel's own `pt_regs` struct. Four of the five links check out exactly. The fifth is where the story gets interesting.\n\nThe chain starts with CVE-2026-99999, published October 15, 2026, CVSS 3.1 score 9.3, assigned by the Linux CNA. The description is short and ugly: a packet with bad checksum metadata reaches the IPv4 stack, `skb_checksum_help` corrupts the network header, \"and cause a bunch of mischief.\" It was discovered by Paulos Yibelo of Pwn.ai while working on Vercel's $1 million sandbox challenge — Vercel's sandboxes run on KVM-based Firecracker microVMs, which is why the researcher had a Firecracker target at hand.\n\nI pulled the fix commit, `6785011f8b16`, written by Michael S. Tsirkin. It is 44 lines added, 12 removed, across exactly 6 files — the same 6 files the CVE record lists as affected:\n\n```\ninclude/net/ip.h\nnet/bridge/netfilter/nf_conntrack_bridge.c\nnet/ipv4/ip_output.c\nnet/netfilter/nfnetlink_queue.c\nnet/netfilter/xt_CHECKSUM.c\nnet/xfrm/xfrm_output.c\n```\n\nThe commit message is unusually honest for a security fix: \"A more complete validation at input is forthcoming, but needs more work.\" The fix checks `checksum_start` before completing the checksum — defense in depth, not a root-cause repair. Fixed stable releases: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.57, and 7.2.11. AWS's bulletin (2026-137-AWS) says its managed EC2, Lambda, and Fargate are not affected — but self-managed KVM hosts, including Firecracker, on unpatched kernels are. That split is the whole story: the vulnerability is in the host kernel, so updating the guest does nothing.\n\nPwn.ai's Part 2 post walks the chain from a host-memory read primitive (Part 1) to full takeover of the Firecracker process. Here is each hop, with what I verified:\n\n**1. Guest page to host page.** The guest plants a nonce in a page, then walks candidate EPT roots to translate its guest physical address to a host physical address. Recorded result: GPA `0x08f03000` → HPA `0x165610000`. I can't verify the addresses — they're run-specific — but the mechanism is standard EPT walking, and the CVE's scenario text confirms the same path: guest-crafted virtio-net checksum metadata reaches the host TAP, `tun_get_user()` feeds the skb to the IPv4 stack.\n\n**2. Host page to Firecracker process.** A reverse page-table walk finds which host process maps that page, recovering its PGD (`0x14afc2000`). Then the ELF image is identified by a known byte sequence in Firecracker's `write(2)` wrapper, giving a load bias (`0x7298c2400000`) under ASLR. I checked the v1.16.1 release exists — published July 2, 2026 — and that the binary links libc (`libc = \"0.2.186\"` in the vmm crate), so a `write` wrapper address is a real thing to find.\n\n**3. The live vCPU frame.** The frame finder searches host memory for a `pt_regs` frame matching an active `KVM_RUN` ioctl. I verified the struct in the kernel source — `arch/x86/include/asm/ptrace.h` has exactly the fields the finder checks:\n\n```\nstruct pt_regs {\n    unsigned long bx, cx, dx, si, di, bp, ax;\n    /* ... segment registers ... */\n    unsigned long orig_ax;\n    unsigned long ip;\n    unsigned short cs;\n    unsigned long flags;\n    unsigned long sp;\n    unsigned short ss;\n};\n```\n\nThe saved `ip` says where the thread resumes, the saved `sp` says which stack it uses. That is the whole attack surface in one struct: whoever controls `pt_regs` controls the thread.\n\n**4. The KVM_RUN return.** This is the hop I could check most concretely. In Firecracker v1.16.1, the vCPU thread's main loop is in `src/vmm/src/vstate/vcpu.rs`. `run()` applies the seccomp filter, then `running()` loops on `run_emulation()`, which calls `self.kvm_vcpu.fd.run()` — the `KVM_RUN` ioctl — and handles the exit:\n\n``` js\nmatch self.kvm_vcpu.fd.run() {\n    Err(ref err) if err.errno() == libc::EINTR => { /* ... */ }\n    emulation_result => handle_kvm_exit(&mut self.kvm_vcpu.peripherals, emulation_result),\n}\n```\n\nSo the thread really does sit inside that ioctl while the guest runs, with its userspace registers saved in exactly the frame the researchers targeted. The exploit rewrites the frame to point at the `write` wrapper with fd 2 (stderr), a buffer holding the 8-byte marker `N8V23M2\\n`, then a `xor eax, eax; ret` gadget to normalize the return value — `write` returns 8, `KVM_RUN` returns 0 — before jumping back to the ioctl continuation. A serial-port write from the guest triggers the return. The host captured exactly 8 bytes on Firecracker's stderr, PID 2936 still alive, guest SSH still responsive, uptime 1615.72 seconds, all three stack words restored.\n\n**5. Root.** The target ran Firecracker v1.16.1 directly as root under `systemd-run`, so the controlled call executed as root. The researchers are explicit that the configuration had no jailer, and that production containment — dropping privileges, namespaces, seccomp — \"requires a separate assessment.\" I checked the jailer source: it does chroot plus a new mount namespace with `pivot_root`. The jailer is a real second line of defense, and this demo ran without it.\n\nThree things, stated plainly. I did not verify the ROP gadget bytes or the frame address — those are run-specific and need a live Firecracker, which I don't have. The host kernel `7.0.0-1011-aws` is the researchers' stated target config; the naming pattern matches AWS kernels, but I didn't independently confirm that build. And the guest kernel `6.18.44+` predates the 6.18.57 fix release, which is consistent with the escape working — but \"consistent with\" is not \"confirmed.\"\n\nOne more scope note: secondary coverage says host memory disclosure was demonstrated against Vercel's production sandbox, but Pwn.ai's own post does not make that claim — it describes a controlled lab setup. Vercel confirmed the findings and said no reports showed access to customer files, secrets, or application data. I am not repeating the stronger claim as fact.\n\nThe escape needs two failures stacked: an unpatched host kernel *and* a Firecracker running without its jailer. Either one alone stops this exact chain — the CVE fix closes the memory primitive, and the jailer means a compromised VMM process is still contained. The uncomfortable part is how small the kernel fix is: 44 lines, explicitly described as partial, with the real input validation still to come. If you run your own KVM or Firecracker hosts, the patch-and-reboot is the action; the guest kernel version is irrelevant. And if you run Firecracker without the jailer because it's simpler, this is the post that prices that shortcut: the difference between \"the guest escaped the VM\" and \"the guest owns the host\" was a configuration flag.\n\nSources: CVE-2026-99999 record (cveawg.mitre.org, published 2026-10-15, CVSS 3.1 9.3); kernel fix commit 6785011f8b16 (44 insertions, 12 deletions, 6 files); Pwn.ai, \"Firecracker VM Escape: PwnEscape Part 2\" (2026-11-06) and Part 1; AWS Security Bulletin 2026-137-AWS; Firecracker v1.16.1 source (`src/vmm/src/vstate/vcpu.rs`, `src/jailer/`); Linux `arch/x86/include/asm/ptrace.h`. The `pt_regs` fields, the `KVM_RUN` call site, the jailer code, the fix diff stats, and the release date I checked myself on 2026-11-06; the escape's run-specific addresses and outputs are the researchers' recorded values.", "url": "https://wpnews.pro/news/9-3-to-root-in-5-hops-i-audited-the-firecracker-escape", "canonical_source": "https://dev.to/frankchu/93-to-root-in-5-hops-i-audited-the-firecracker-escape-4fhn", "published_at": "2026-11-07 00:40:05+00:00", "updated_at": "2026-11-07 00:52:45.165005+00:00", "lang": "en", "topics": ["ai-safety", "ai-infrastructure", "artificial-intelligence"], "entities": ["Firecracker", "Pwn.ai", "Paulos Yibelo", "Vercel", "Michael S. Tsirkin", "AWS", "Linux", "KVM"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/9-3-to-root-in-5-hops-i-audited-the-firecracker-escape", "markdown": "https://wpnews.pro/news/9-3-to-root-in-5-hops-i-audited-the-firecracker-escape.md", "text": "https://wpnews.pro/news/9-3-to-root-in-5-hops-i-audited-the-firecracker-escape.txt", "jsonld": "https://wpnews.pro/news/9-3-to-root-in-5-hops-i-audited-the-firecracker-escape.jsonld"}}