Magic Tools
Developer ToolsBy CooconAugust 8, 2026151 views4 min read

Zapscape: The KVM Escape Bug That Sat in Plain Sight for Six Years

Zapscape: The KVM Escape Bug That Sat in Plain Sight for Six Years

You spin up a $5 VM on your cloud provider. The physical box you land on is also hosting a dozen other tenants—startups, banks, maybe a competitor. KVM draws the line between you and them. Your memory, their memory. Your keys, their keys. Never the twain shall meet.

That line held until Zapscape.

CVE-2026-64561, found by Hyunwoo Kim (@v4bel), lets a guest break out to the host with kernel-level privileges. One compromised VM owns the entire physical machine—and every other VM sitting on it.

The bug lived in the Linux kernel from July 2020 to July 2026. Six years, nobody noticed.

The bug, explained without the kernel jargon

Nested virtualization—a VM inside a VM—asks for more address translation than the hardware can do on its own. So KVM builds software shadow page tables to track what L1's page tables say about L2's memory.

Each shadow page has a struct called kvm_mmu_page. Two fields matter here:

root_count: how many vCPUs are using this page as their root. Anything above zero means the reclaimer leaves it alone.

parent_ptes: a pointer to the parent page table. When the last parent goes away, the child can be cleaned up.

Normal reclamation works like you'd expect: memory runs low → walk the active list → skip pages with root_count > 0 → zap the rest. Clean, safe.

There's a second path, though. When KVM removes a parent page table entry, it checks whether the child is in nested guest mode and has no remaining parents; if both hold, it recursively zaps the child. And here's the kicker: that path never checks root_count.

So an attacker engineers a single shadow page X that is simultaneously a child of one nested page table and the root of another. Clean up X's parent, watch the recursive path zap X, and vCPUs keep writing into freed memory. That's your use-after-free.

The rest of the chain gets creative: two cross-cache operations to stretch the UAF, a KASLR bypass, then a hop through the kernel's log_wait, SRCU workqueue, and usermode helper to drop a root-owned file on the host. The PoC writes /Zapscape. Swapping that for a reverse shell is an afternoon's work.

An analogy. Think of a co-working space. Each company gets a locked floor. Building management (KVM) has one rule: don't touch occupied meeting rooms. But one janitor (the recursive reclamation path) never checks the booking system—they only look at whether the company nameplate has been scratched off the door. The attacker hangs two nameplates on the same room. The janitor sees one scratched off, assumes the room is free, and dismantles it mid-meeting. Now the attacker walks through the debris into the server room and grabs the master key.

Not just AMD. Intel too.

The public PoC targets AMD SVM/NPT on Linux 7.1.3, but the vulnerable code sits in the shared shadow MMU that Intel and AMD both use. Triggering it on Intel needs L1 to expose EPT page walk lengths of both 4 and 5—hardly an exotic configuration.

Then there's the part that annoys me most. On RHEL and derivatives, /dev/kvm ships with permissions 0666: any local user can open it. That turns Zapscape from a cloud escape into a plain local privilege escalation, no VM required. Those permission bits have been indefensible for years, and Zapscape just made the bill come due.

What's actually at stake

Running KVM as a provider? Patch now, patch everywhere. Every KVM/x86 host with nested virtualization enabled is in scope.

Building on someone else's cloud? Your security boundary is their kernel version. Ask them. Then ask again next quarter.

Self-hosting KVM? You have the most to lose and the slowest patch cycle. Move this to the top of the list.

v4bel's own words: the public PoC isn't a drop-in cloud weapon, but "moving the L1 actions into a guest kernel module and porting the exploit to match the host kernel's kconfig is not a difficult task." That's researcher-speak for "someone has probably already done it."

The pattern that should worry you

Zapscape isn't v4bel's first KVM escape. Earlier this year the same researcher published Januscape (CVE-2026-53359)—another escape, also in the shadow MMU. Two escapes, one subsystem, one year, one researcher.

That's not bad luck. That's a signal.

Shadow MMU code has been running in production kernels for decades without the sustained security scrutiny newer subsystems attract. My bet: there's more in there, and we hear about it before the year is out.

What you should do today

Check your kernel.

uname -r

If the July 21 fix isn't in, patch. On cloud VMs, check the provider's status page—and don't assume "managed" means "already handled."

Kill nested virtualization where you don't need it.

lsmod | grep kvm

Running KVM inside a VM is niche. If you didn't turn it on deliberately, turn it off.

Lock down /dev/kvm.

ls -la /dev/kvm

0666 is a local root waiting to happen. 0660 covers most setups.


Virtualization isn't magic. Your sandbox is only as strong as the code enforcing it, and that code missed a root_count check for six years.

Run those three checks today. Then go find the next thing you've been trusting without ever verifying it.

Sources:

✨ Draft generated by DeepSeek, reviewed and polished by Claude.

Related Articles

Dev Breakfast · 2026-09-23

Today's headline: Git 2.56 is Coming, 3.0 Will Default to Replace SHA-1: GitHub Hasn't Caught Up. Plus 7 more: WordPress Unauthenticated Path Traversal, Conditional RCE Pending; Google AX Hits 2324 Stars: Don't Rush to Production; and more.

daily-intelSep 23, 20269 min
8

Dev Breakfast · 2026-09-22

Today's headline: Test volume quadrupled, PR wait only dropped from 6 minutes to 5 minutes. Plus 7 more: Sandboxing isn't black magic: figure out who to lock up first; On the day MCP was questioned, five articles criticizing AI topped the charts simultaneously; and more.

daily-intelSep 22, 20267 min
47

Dev Breakfast · 2026-09-21

Today's headline: ChatGPT's ad Cookie cross-site tracking: 936 pixels, 1029 domains. Plus 7 more: AI Studio only deletes local pointers when deleting data, reporter banned in 60 seconds; Mac M4 runs Jev offline: CoreML makes 45 decisions per second; and more.

daily-intelSep 21, 20269 min
73

DeepSeek Says 1M, Claude Code Says 200K: I Measured Both and Neither Number Is the Real Limit

DeepSeek advertises a 1M context window. Point Claude Code at it and Claude Code reports contextWindow 200000 for the same model. I measured what actually happens. DeepSeek's real ceiling is 1,048,576 tokens — literally 2^20, not one million — and it covers input plus your max_tokens budget, proven with a controlled pair. A needle planted at position zero was retrieved correctly at 1,039,744 tokens. Claude Code refuses client-side long before that, in 25ms with zero API calls, and its gate is not on tokens at all: it fires at roughly 480,000 characters. Feed it high-entropy text and 478,000 characters sails through carrying 309,567 real tokens — 55% past the 200K window it just claimed. And in ordinary use you reach none of these, because Bash output over exactly 30,000 characters never enters context at all.

claude-codelong-context+5
hands-onSep 20, 20267 min
56

Published by Magic Tools