critical

CVE

CVE-2026-53359

CWE

CWE-416, CWE-362

Affected Surface

Linux KVM/x86 hosts carrying the vulnerable shadow MMU code from 2.6.36 until branch-specific fixes such as 6.1.177, 6.6.144, 6.12.95, 6.18.38, or 7.1.3, Intel VMX/EPT and AMD SVM/NPT virtualization hosts that allow untrusted guests to use nested virtualization, where KVM must shadow guest-managed nested page tables in software, Distributions or developer systems that expose `/dev/kvm` broadly enough for local unprivileged users to reach KVM and turn the bug into a host-local root path, CI, build, research, or cloud environments where attacker-controlled code can first gain code execution inside a guest or local VM-enabled workload

CVE-2026-53359, now public as Januscape, is one of the most important Linux disclosures from the last several days because it is not “just” another local kernel bug. It is a guest-to-host KVM/x86 escape that the public researcher write-up says was already used as a zero-day in Google’s kvmCTF, and it works against both Intel and AMD virtualization paths because the vulnerable logic sits in shared KVM shadow-MMU code rather than in a vendor-specific backend.

This matters for AppSec teams because the initial foothold does not need to be a hypervisor bug. A package compromise, build-step backdoor, or ordinary application exploit that lands code execution inside a guest can use Januscape as the next privilege boundary crossing. In other words, an npm or PyPI infection that reaches a Linux build VM can hand the attacker the guest foothold; Januscape can hand them the host.

What is actually affected

The public metadata is broader than the most likely practical exploit surface, so it helps to separate the two.

NVD tracks the vulnerable code as present from Linux 2.6.36 forward until branch-specific fixes land, with stable fixed points including:

6.1.177
6.6.144
6.12.95
6.18.38
7.1.3
7.2-rc1 and later

The exploitability boundary is narrower than “every Linux machine on those versions”. Januscape lives in KVM/x86 shadow MMU handling, and the public write-up makes the key operational point explicit: the dangerous path is reached when KVM has to shadow guest-controlled nested page tables in software.

That makes the highest-risk environments:

  • public-cloud or private-cloud KVM hosts that accept untrusted guests
  • virtualization labs that enable nested virtualization
  • CI or research hosts running attacker-controlled VMs
  • desktop or server systems that expose /dev/kvm to low-privilege users

The disclosure is especially relevant to Linux application-security teams because some environments collapse these boundaries. The oss-security post calls out distributions where /dev/kvm is permissive enough that an unprivileged local user can potentially turn Januscape into a host-local root path. So even outside classic multi-tenant cloud, a malicious local workload can matter.

Root cause: kvm_mmu_get_child_sp() reused a shadow page by GFN, but ignored its role

The bug lives in arch/x86/kvm/mmu/mmu.c, in the path KVM uses to obtain the next shadow page while walking guest-controlled page tables.

The vulnerable logic, simplified to the relevant decision, looks like this:

static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu,
                                                 u64 *sptep, gfn_t gfn,
                                                 bool direct, unsigned int access)
{
    if (is_shadow_present_pte(*sptep) &&
        !is_large_pte(*sptep) &&
        spte_to_child_sp(*sptep) &&
        spte_to_child_sp(*sptep)->gfn == gfn) {
        return ERR_PTR(-EEXIST);
    }

    role = kvm_mmu_child_role(sptep, direct, access);
    return kvm_mmu_get_shadow_page(vcpu, gfn, role);
}

The problem is the reuse check. It only asks whether the existing child shadow page has the same guest frame number (gfn). It does not verify whether that child page has the same role.

That role distinction is the whole bug:

  • direct=0 means the shadow page represents a guest page table
  • direct=1 means the shadow page came from splitting a large page into 4 KB entries

Those are not interchangeable, even if the GFN matches.

The upstream fix is conceptually simple: only reuse the child shadow page if both the GFN and the role match. The public researcher write-up and the mainline patch both reduce to this rule:

role = kvm_mmu_child_role(sptep, direct, access);

if (is_shadow_present_pte(*sptep) &&
    !is_large_pte(*sptep) &&
    spte_to_child_sp(*sptep) &&
    spte_to_child_sp(*sptep)->gfn == gfn &&
    spte_to_child_sp(*sptep)->role.word == role.word) {
    return ERR_PTR(-EEXIST);
}

Without that role check, KVM can incorrectly reuse a shadow page built for one translation mode while the current walk expects the other.

Why nested virtualization is the real attack surface

A lot of Linux systems run with hardware-assisted paging enabled, so at first glance teams may assume ordinary EPT/NPT setups are enough protection. Januscape matters because the vulnerable path is not the common “plain guest on a modern host” fast path. It is the nested case.

The public write-up explains the pivot:

L0 host runs KVM
-> L1 guest becomes a hypervisor
-> L1 creates nested EPT/NPT for L2
-> L0 must shadow that guest-controlled nested page-table tree in software
-> shadow MMU path reaches kvm_mmu_get_child_sp()

That is why this bug is so operationally important for cloud and research environments. You can have hardware paging enabled globally and still hit the vulnerable shadow-MMU logic when a guest is allowed to run its own nested guest.

How the public exploit turns role confusion into host corruption

Januscape is not “just” a correctness bug. The public material explains a concrete corruption chain.

The proof-of-concept creates a state where the same GFN is used in two incompatible ways:

  1. as a large-page mapping
  2. as a page-table page

That forces the shadow-MMU fetch path to request the same GFN under two different roles. Because the old reuse logic only compares the GFN, KVM can return the wrong page type and poison its own internal bookkeeping.

The high-level path is:

role mismatch in child shadow-page reuse
-> wrong shadow page reused
-> reverse-map bookkeeping diverges
-> leaf SPTE recorded under one GFN
-> teardown later computes a different GFN
-> stale rmap entry survives after page free
-> later host-side walk dereferences an SPTE inside freed memory
-> use-after-free and host memory corruption

NVD’s description captures the exact mismatch: after the wrong page is reused, the leaf SPTE can be recorded under the GFN resolved by the current walk, but later teardown computes the GFN from a direct-page assumption (sp->gfn + index) instead of the stored shadowed translation. That means cleanup removes the wrong reverse-map entry, leaving a stale pointer into freed host memory.

The public PoC is guest-controlled and dual-arch

One of the most important practical details in the disclosure is that the exploit path is guest-driven. The PoC does not require a cooperating userspace VMM bug, and it is not limited to one CPU vendor.

The disclosure and write-up describe the PoC structure like this:

L1 guest loads a kernel module
-> module builds nested page tables for an L2 guest
-> same physical page is arranged to serve as both a huge-page target and a page-table page
-> L2 faults force L0 to shadow the nested tables
-> the role-confusion path fires inside host KVM
-> host corrupts shadow-MMU state and panics or becomes exploitable

The architecture-independence is also material. The public exploit swaps only the page-table bit encoding between:

Intel: VMX + EPT
AMD:   SVM + NPT

The vulnerable logic itself stays the same because kvm_mmu_get_child_sp() is in shared x86 KVM MMU code. That is why the researcher and SecurityWeek both call out Januscape as a rare public guest-to-host result that reaches both Intel and AMD hosts.

Why this is an AppSec problem, not only an infrastructure problem

The Linux host is the final trust boundary here, but AppSec teams should read Januscape as a second-stage privilege amplifier.

The initial code execution can come from somewhere much more familiar:

malicious npm dependency in a build VM
trojanized PyPI wheel in a research guest
CI runner compromise inside a nested lab environment
application RCE inside a guest image
low-privilege shell on a developer workstation with broad /dev/kvm access

Once the attacker is inside the guest, the next question becomes whether they can reach the host kernel. Januscape provides that bridge on affected systems.

This chaining model is exactly why local Linux privilege-escalation bugs still matter to application-security programs. We already called out the same “post-foothold privilege amplifier” pattern in Bad Epoll and Dirty Frag, but Januscape is arguably worse for cloud environments because it is a guest-to-host boundary crossing, not only a same-host local root.

Scoping and mitigation

There is no meaningful runtime mitigation for the underlying logic flaw. The right response is to identify hosts that combine:

  1. vulnerable KVM/x86 kernels
  2. nested virtualization exposure or broad local KVM access
  3. untrusted code execution in guests or local VM-capable workloads

Start with version and access checks:

uname -r
ls -l /dev/kvm
lsmod | rg '^kvm(_intel|_amd)?'

Then confirm whether nested virtualization is enabled:

for p in /sys/module/kvm_intel/parameters/nested /sys/module/kvm_amd/parameters/nested; do
  [ -e "$p" ] && printf "%s=%s\n" "$p" "$(tr -d '\n' < "$p")"
done

For distro kernels, verify the backport instead of relying only on the major/minor branch:

rpm -q --changelog kernel | rg 'CVE-2026-53359|81ccda30b4e8'
apt changelog "linux-image-$(uname -r)" 2>/dev/null | rg 'CVE-2026-53359|KVM: x86: Fix shadow paging use-after-free'

If your environment runs untrusted guests, nested virtualization, or VM-capable local workloads, prioritize the stable lines NVD now tracks as fixed:

6.1.177
6.6.144
6.12.95
6.18.38
7.1.3

Treat guest environments that may already have run hostile code as incident-response candidates, not only patch-management tasks. If the attacker could already execute inside a guest, Januscape may have let them cross into the host before you patched.

The short version is that Januscape is not a bug you triage like an obscure kernel edge case. It is a newly public, technically detailed, cross-vendor KVM escape that turns “attacker got code execution inside one Linux guest” into “attacker may own the virtualization host and every adjacent tenant.”

References