Blog
KVM EscapeCVE-2026-64561Linux KernelVirtualization Security

Zapscape CVE-2026-64561: a Second KVM Escape in Five Weeks

Zapscape is a use-after-free in the KVM shadow MMU that turns guest kernel access into host root. It is the third escape in that same subsystem since May — patching one CVE is not patching the class.

Zero Hunt Research··9 min read

On 6 August 2026, security researcher Hyunwoo Kim published Zapscape — CVE-2026-64561, a use-after-free in the Linux KVM/x86 shadow MMU that lets code with kernel privilege inside a guest write into freed host kernel memory and take over the hypervisor. Proof-of-concept code went public the same day. If you run virtualization on Linux — and if you run anything on Linux, you probably do — the interesting part is not this single bug. It is that Zapscape is the third use-after-free in KVM's shadow paging code disclosed since late May, from the same subsystem, with the same impact, and the fix for the previous one does not fix this one.

What Zapscape actually breaks

KVM's shadow MMU maintains host-side page tables that translate guest memory addresses. When the hypervisor runs low on shadow pages, it reclaims them: it zaps pages, recursively walking down and tearing out child entries.

The bug is an ordering mistake in that path. KVM checked whether the current MMU root was stale before it made more pages available. Reclaiming pages could then invalidate that very root — but KVM kept walking the fault path anyway. Child shadow pages inherited invalid state and left dangling list links behind, and an attacker who controls the timing gets a write into memory the kernel has already freed. The NVD entry states the invariant that was violated plainly: invalid pages should never be on the active MMU pages list.

The upstream fix moves the stale-root check to after page availability is assessed, and restarts the fault (RET_PF_RETRY) when reclaim invalidated a root. It landed on 21 July 2026, sixteen days before public disclosure.

The vulnerable window runs from commit f95eec9bed76 (8 July 2020) to that fix — Linux 5.9 onward, roughly six years of shipped kernels. Red Hat's preliminary score is CVSS 7.0 with vector AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H. Do not let the 7.0 anchor your response. "High attack complexity, local, low privileges required" is exactly what a hypervisor escape looks like in CVSS terms, and CVSS does not model the blast radius of losing the host under thirty tenants.

The preconditions decide whether you care

This is not a bug that fires on every KVM box, and the difference matters more than the score:

  • Guest kernel privilege (L1) is required. The attacker must already be root inside a VM. On a multi-tenant host, that is not a hurdle — it is the product you sold them.
  • Nested virtualization must be exposed to the guest. No nested virt, no reachable path.
  • On Intel, exploitation requires both EPT page-walk lengths 4 and 5 exposed to L1. On AMD (SVM/NPT), the researcher's own write-up describes the surface as broader, and the published PoC targets AMD.

Then there is the precondition that catches people who think none of this applies to them. On distributions where /dev/kvm is world-writable — mode 0666, the default on Red Hat–family systems — an unprivileged local user can exploit this without any pre-existing VM at all. They create their own guest, become root inside it (their own VM, trivially), and use the escape as a local privilege escalation to root on the host. Phoronix's coverage flags this dual impact directly. A build server, a CI runner, a shared developer box, a workstation with a permissive /dev/kvm — none of these are "hypervisors" in anyone's asset inventory, and all of them are in scope.

Three escapes in the same subsystem in ten weeks

Zapscape is not an isolated finding. Pull the shadow-MMU disclosures of this quarter into one view:

CVE Name Mechanism Fixed / disclosed
CVE-2026-46113 Shadow MMU computes GFNs from sp->gfn + SPTE index; breaks when guest page tables change between VM entries, leaving stale rmap entries after a kvm_mmu_page is freed. CVSS 8.8, scope-changed. Published 28 May 2026
CVE-2026-53359 Januscape Shadow page frame-number / role confusion — host binds a shadow PTE to the wrong guest frame. First KVM escape demonstrated on both Intel and AMD; shown as a zero-day in Google's kvmCTF. Bug dated to 2010. Upstream 16 June, stable 4 July 2026
CVE-2026-64561 Zapscape Use-after-free in the recursive zap path; stale-root check ordered before page reclaim. Upstream 21 July, public 6 Aug 2026

The same researcher also published ITScape (CVE-2026-46316) against KVM/arm64. And the lineage runs back much further — CVE-2019-7221 (KVM VMX preemption timer use-after-free) and CVE-2021-22543 (VM_IO|VM_PFNMAP handling that let pages be freed while still accessible to the VMM) are the same shape of defect in the same trust boundary.

An internal note, offered as our own observation rather than an industry statistic: when we queried Zero Hunt's Knowledge RAG for prior art on this bug class before writing, what came back was not one match but that entire chain — 2019, 2021, May 2026, and the current pair. The corpus recognises shadow paging as a recurring soft spot, not a series of coincidences. Shadow MMU code is legacy-heavy, performance-sensitive, and full of lifetime rules enforced by convention rather than by the type system. That is a bug class, and bug classes come back.

Auditor: You reported the KVM escape as remediated on 8 July. Platform engineer: We did. We took the July stable kernels for Januscape across the whole fleet. Auditor: This finding is dated 6 August and it says the same subsystem, guest to host, root on the hypervisor. Platform engineer: Different CVE. The Januscape kernel doesn't carry the Zapscape fix. Auditor: So the control you evidenced last month was true, and the boundary was still open the whole time.

Both people in that exchange are right, which is the problem. "We patched the VM escape" is a statement about a CVE. The auditor is asking about a boundary. Those two things drift apart the moment the class produces its next instance — and this one produced two in five weeks.

Remediation

1. Am I affected?

Check three things: kernel version, whether nested virtualization is exposed, and who can open /dev/kvm.

# Kernel in the affected range? (5.9 through the 21 July 2026 fix)
uname -r

# Is nested virtualization enabled?
cat /sys/module/kvm_intel/parameters/nested 2>/dev/null   # Y/1 = exposed
cat /sys/module/kvm_amd/parameters/nested   2>/dev/null   # Y/1 = exposed

# Who can reach the interface? 0666 = every local user is in scope
stat -c '%a %U:%G' /dev/kvm
getent group kvm

You are exposed to the escape path if the kernel is unpatched and nested virt is on. You are additionally exposed to the local-privilege-escalation path if /dev/kvm is 0666, regardless of whether you run any guests.

2. Patch — exact fixed versions

The fixed stable releases published at disclosure are 6.6.148, 6.12.101, 6.18.42, 7.1.6 and 7.2-rc5. Note what is not on that list: the affected range starts at 5.9, so older maintained branches (5.10, 5.15, 6.1) are in scope but had no fixed stable release enumerated at disclosure time — check your distribution's CVE tracker for the backport rather than assuming coverage. Verify by version, not by "we ran updates": a kernel package installed but not booted is an unpatched host.

If you took the Januscape stable kernels on 4 July (7.1.3, 6.18.38, 6.12.95, 6.6.144, 6.1.177, 5.15.211, 5.10.260), you are not covered for Zapscape. Those predate the 21 July fix.

3. Can't reboot now? Compensating controls

Both are effective and both are cheap:

# Turn nested virtualization off (requires no running guests on the module)
echo 'options kvm_intel nested=0' > /etc/modprobe.d/kvm-nested.conf
echo 'options kvm_amd nested=0'  >> /etc/modprobe.d/kvm-nested.conf

# Close the local-user path: restrict /dev/kvm to the kvm group
printf 'KERNEL=="kvm", GROUP="kvm", MODE="0660"\n' > /etc/udev/rules.d/65-kvm.rules
udevadm control --reload && udevadm trigger --name-match=kvm

Disabling nested virt removes the precondition for the escape entirely. Tightening /dev/kvm to 0660 removes the unprivileged-user LPE path on non-hypervisor machines — where, in most estates, nobody needed world access in the first place. Live patching (kpatch, kernelcare, ksplice) is the third option where your vendor ships this fix; confirm the specific CVE is included before recording it as remediated.

4. Hunt for compromise

There is very little wire-side signal here — the whole attack happens inside one physical machine, so this is a host-telemetry hunt. Map to MITRE ATT&CK T1611 (Escape to Host), T1068 (Exploitation for Privilege Escalation), and, post-escape, T1014 (Rootkit), T1562.001 (Impair Defenses) and T1005 (Data from Local System — co-tenant disk images and secrets are the payoff).

# Failed exploitation is loud: KVM/MMU oopses, GPFs, KASAN reports
journalctl -k --since "2026-05-01" | grep -iE 'kvm|mmu|BUG:|general protection|KASAN|Oops'

# A tainted kernel that nobody explains is a finding
cat /proc/sys/kernel/tainted

# Unexpected openers of /dev/kvm, and guests that suddenly need nested virt
fuser -v /dev/kvm 2>&1
grep -rlE '<cpu.*(vmx|svm)' /etc/libvirt/qemu/ 2>/dev/null

Signals worth escalating: repeated KVM MMU oopses on a host with untrusted guests; a guest whose configuration acquired nested virtualization without a change ticket; /dev/kvm opened by a service account or a build job that has no business creating VMs; and any new kernel module loaded on the host around those events.

5. Eradicate and verify

If you find evidence of a successful escape, the host kernel was executing attacker-controlled code — the host is the compromised asset, not the guest. Rebuild it. Do not migrate the guests to a clean host first and assume the problem moved with them; treat the host's secrets as disclosed. In order:

  1. Evacuate workloads to a patched host, isolating the suspect guest rather than resuming it.
  2. Rebuild the host from known-good media, then patch before it re-enters the pool.
  3. Rotate everything the host held: hypervisor management credentials, storage and backup-network keys, host TLS material, any token in a co-tenant VM's disk image that the attacker could read.
  4. Verify after patching, by absence and by version:
uname -r                                          # must be >= the fixed release
cat /sys/module/kvm_*/parameters/nested           # expect N/0 where you disabled it
stat -c '%a' /dev/kvm                             # expect 660

Where Zero Hunt fits

The operational question this article opened with is not "which CVE do I patch". It is "can a foothold inside one of my guests reach my host — today, on the kernel I am actually booted into, with the nested-virt settings I actually have?" That question does not survive a quarterly assessment, because the answer changed twice in the last five weeks.

Zero Hunt's 10-agent swarm is built to answer that class of question continuously rather than by CVE lookup. The Post-Exploit and Pivot agents do not stop at "a vulnerable package version is installed" — they establish a foothold and test where it reaches, which is the difference between a scanner asserting exposure and evidence that a boundary held or did not. Exploits are generated per target by a local LLM rather than pulled from a public database, so a validation run reflects your kernel, your hypervisor configuration and your /dev/kvm permissions instead of a generic PoC's assumptions. Every skill is backtested in AI Gym — 142+ self-evolving skills, run against Vulhub, NYU CTF Bench and Vulhub-Bench — before it is allowed near a production environment, and change-triggered campaigns re-run validation when a host's configuration moves, not three months later.

There is a self-referential point here worth stating plainly, because this article is about isolation boundaries failing. Zero Hunt runs every exploit inside an ephemeral Docker container with optional gVisor hardening, on a hardened appliance host, entirely on-premise — no cloud callbacks, no external LLM APIs, air-gap supported. A validation platform that executes attack code has to answer the same question it asks of you, and executing it on someone else's shared infrastructure is not an answer.

The compliance side follows from the same evidence. Kernel fix level, nested-virt exposure and device permissions are controls under ISO 27001, NIS2 and CIS simultaneously; Zero Hunt maps each finding and each remediation across all 32 frameworks and signs the record with ECDSA at write time. That is what turns the exchange in the blockquote above from an argument into a timeline — one that shows precisely which hosts were on which kernel on which date, and when the boundary was actually closed.

If your estate runs multi-tenant KVM, or just a lot of Linux boxes with a permissive /dev/kvm, get in touch — or read how the platform validates exploitability rather than inferring it.