A forgotten cache key lets you rewrite kernel memory the way a lost hotel master-key lets you open every door on the floor
CVE-2026-74580 — branded *Vghost* by Tencent Zhuque Lab — is a stale metadata-cache flaw in the Linux kernel's vhost virtualization-acceleration subsystem, present since kernel 4.11 (2017) through 7.2-rc4. When a user reconfigures a virtual ring via VHOST_SET_VRING_ADDR or VHOST_SET_VRING_NUM, the per-queue IOTLB cache (vq->meta_iotlb[]) is not invalidated. Subsequent operations hit the stale cache, skip validation, and translate new addresses through old mappings — yielding deterministic, race-free arbitrary kernel read/write. From there the attacker reads the IDT to bypass KASLR and overwrites modprobe_path for instant root. A second exploitation vector targets KVM/QEMU hosts with virtual IOMMU: a guest triggers VIRTIO_F_RING_RESET, forcing the host's QEMU process to re-issue VHOST_SET_VRING_ADDR without cache reset, corrupting the QEMU heap and hijacking QOM method tables for guest-to-host escape. Affected versions: Linux 4.11 – 7.2-rc4. Fixed in stable branches 5.10.265, 5.15.216, 6.1.183, 6.6.152, 6.12.104, 6.18.45, 7.1.9, 7.2.
The vendor (kernel.org CNA) rates this HIGH 8.8 with a Scope-Changed vector (S:C). That score is defensible for the general Linux population, but it under-weights the hypervisor blast radius. The vhost subsystem exists solely to accelerate virtio I/O for virtual machines — its canonical deployment IS the hypervisor host. On RHEL 9.8, Amazon Linux 2023, Azure Linux 3.0, and Oracle Linux 10.2, the device nodes /dev/vhost-vsock and /dev/vhost-net ship with 0666 world-accessible permissions, meaning *any* unprivileged shell — a compromised web app, a low-priv container escape, an SSH brute-force — immediately chains to root with a single deterministic exploit. On a hypervisor node, that root equals control of every guest on the box. The PoC is public, race-free, and portable across a decade of kernels. noisgate upgrades this to CRITICAL 9.0.
6 steps from start to impact.
Obtain local shell on target host
/dev/vhost-* with 0666 permissions (RHEL, Amazon Linux, Azure Linux, Oracle Linux). On Ubuntu, membership in the kvm group is needed.- Low-privilege local shell on a Linux host with vhost module loaded or loadable
- Requires initial access — this is not remotely exploitable
- On Ubuntu the device is 0660 root:kvm, limiting to kvm group members
Open vhost device and prime the IOTLB cache
/dev/vhost-vsock (or /dev/vhost-net), sets up a vring, and issues a normal VHOST_SET_VRING_ADDR ioctl to populate vq->meta_iotlb[] with valid IOTLB translations for the descriptor, available, and used ring regions. This is a normal kernel API call; no exploit code is visible yet.- Read/write access to /dev/vhost-vsock or /dev/vhost-net
- None on 0666 distros — the ioctl succeeds for any user
-w /dev/vhost-vsock -p rw); Falco/Tetragon eBPF rules for unexpected vhost ioctl sequencesRepoint vring address without cache invalidation
VHOST_SET_VRING_ADDR ioctl pointing the used-ring address to a target kernel address (e.g., modprobe_path). Because the kernel does not call __vhost_vq_meta_reset(), the old IOTLB cache entry persists. The next iotlb_access_ok() check hits the stale cache and returns success without range validation — the kernel now believes the attacker-chosen address is a legitimate guest mapping.- Stale cache from step 2 still valid
- None — deterministic, race-free; no timing window or heap grooming required
Achieve arbitrary kernel read/write
vring_used_elem at the attacker-chosen address. For reads, repointing desc_user_addr to kernel memory causes vhost to fetch from that address; the first 8 bytes leak via IOTLB miss messages. Both primitives are fully deterministic and repeatable. The PoC (zhangutah/security-research) demonstrates a benign modprobe_path overwrite and restore.- Steps 2-3 completed
- Attacker needs kernel symbol addresses — resolved from /boot/System.map or /proc/kallsyms (readable by default on many distros)
KASLR bypass and root escalation
0xfffffe0000000000 to recover the asm_exc_divide_error handler and calculate the kernel slide, defeating KASLR. Then overwrites modprobe_path to point to an attacker-controlled script, triggers an unknown binary format to invoke modprobe, and gains root execution. The entire chain — from unprivileged user to root — runs in a single process without races or retries.- Arbitrary read/write from step 4
- System.map or /proc/kallsyms readable (default on tested distros)
- Kernel lockdown mode (if enforced) restricts /proc/kallsyms and System.map access
- SELinux in enforcing mode may block modprobe_path overwrite payload execution
VM escape variant (conditional)
iommu_platform=on), an untrusted guest negotiates VIRTIO_F_RING_RESET and triggers a ring reset. The host QEMU process calls VHOST_SET_VRING_ADDR in the host kernel without clearing the vhost metadata cache. The stale mapping extrapolates beyond guest RAM into the host QEMU process heap. Guest-controlled writes corrupt QOM method tables, hijacking QEMU control flow for guest-to-host code execution.- Guest VM on a KVM/QEMU host
- Virtual IOMMU enabled with iommu_platform=on
- VIRTIO_F_RING_RESET support negotiated
- Virtual IOMMU is not the default QEMU configuration — it must be explicitly enabled
- Cloud providers typically use custom hypervisors, not stock QEMU+vhost
- Requires guest kernel cooperation to negotiate the feature flags
chmod 0660 /dev/vhost-net /dev/vhost-vsock and persist via udev rules (KERNEL=="vhost-*", MODE="0660", GROUP="kvm"). This eliminates the unprivileged LPE path entirely — only kvm group members retain access. Deploy within 3 days per noisgate mitigation SLA for CRITICAL findings.echo 'install vhost /bin/true' > /etc/modprobe.d/disable-vhost.conf and unload with modprobe -r vhost_net vhost_vsock vhost_scsi vhost. This removes the attack surface entirely on non-virtualization systems. Deploy within 3 days.iommu_platform=on in the guest's virtio device configuration. Audit libvirt domain XMLs for <driver iommu='on'/> and remove it from guests that don't need device assignment or VFIO passthrough. This eliminates the guest-to-host escape path. Deploy within 3 days.de845981da67: 5.10.265+, 5.15.216+, 6.1.183+, 6.6.152+, 6.12.104+, 6.18.45+, 7.1.9+, or 7.2+. Schedule within 90 days per noisgate remediation SLA for CRITICAL findings. Prioritize hypervisor hosts and multi-tenant infrastructure for the earliest patch wave.-w /dev/vhost-vsock -p rw -k vhost_access and -w /dev/vhost-net -p rw -k vhost_access. Alert on access by UIDs outside the expected virtualization service accounts (libvirtd, QEMU). This does not prevent exploitation but provides forensic visibility and early warning. Deploy within 3 days.- SELinux / AppArmor alone — while MAC policies may restrict post-exploitation payload execution (e.g., blocking the modprobe_path trick), they do not prevent the kernel memory corruption itself. An attacker with arbitrary kernel read/write can disable or bypass MAC enforcement by modifying in-kernel security structures.
- Network segmentation / firewalls — this is a local privilege escalation; there is no network component to block. Firewalls and IDS/IPS provide zero mitigation.
- Kernel lockdown mode — restricts access to /proc/kallsyms and /boot/System.map, which complicates KASLR bypass. However, the PoC includes a fallback to hardcoded IDT addresses at
0xfffffe0000000000, and kernel lockdown is not enabled by default on any tested distribution. - Container namespaces without device-cgroup — standard container isolation (PID/network/mount namespaces) does not prevent access to /dev/vhost-* if the device is bind-mounted or the container runs with elevated device access. Only explicit device-cgroup deny rules or
--devicerestrictions prevent container-based exploitation.
The supporting signals.
| In-the-wild status | No confirmed exploitation as of 2026-10-16. Not listed in CISA KEV. Tencent Zhuque Lab disclosed full technical details and working demonstrations on 2026-10-12, with oss-security post on 2026-10-14. The deterministic, race-free nature of the exploit and public PoC make weaponization trivial. |
|---|---|
| Proof-of-concept | Public and functional. Tencent Zhuque Lab published a full write-up at matrix.tencent.com. PoC code at zhangutah/security-research — a benign modprobe_path overwrite/restore against /dev/vhost-vsock. Also indexed on Sploitus. The exploit requires no heap grooming, no race conditions, and no kernel-structure-layout dependencies — it is portable across a decade of kernels. |
| EPSS | 0.00126 (~60th percentile). Low model confidence likely reflects the local-only attack vector and recent PoC disclosure (2026-10-12). Expect this to climb as exploit tooling propagates. |
| KEV status | Not listed as of 2026-10-16. Given no confirmed in-the-wild exploitation yet, KEV addition is not imminent but should be monitored. |
| CVSS vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H = 8.8 HIGH. S:C (Scope Changed) reflects the cross-boundary impact: unprivileged user → kernel, or guest → host. AC:L is accurate — the exploit is deterministic with no race condition. PR:L is accurate for most distros with 0666 device permissions. |
| Affected versions | Linux kernel 4.11 through 7.2-rc4. Introduced by commit f88949138058 (v4.11, O(1) metadata cache) compounded by 0210a8db2aec (v5.9, deferred GIOVA validation). Fixed in stable branches: 5.10.265, 5.15.216, 6.1.183, 6.6.152, 6.12.104, 6.18.45, 7.1.9, 7.2. Upstream fix: commit de845981da67. |
| Distro patch status | Ubuntu 22.04: fixed (5.15.0-198.208). Ubuntu 24.04/26.04: vulnerable, patches in progress. Debian Bookworm: fixed (6.1.187-1). Debian Trixie: fixed (6.12.107-1). RHEL 9.8: fix pending (Red Hat Bugzilla 2521055). Amazon Linux 2023: fix pending. Oracle Linux: fix pending. |
| Device permissions | Critical detail: /dev/vhost-vsock and /dev/vhost-net ship with 0666 (world read/write) on RHEL 9.8, Amazon Linux 2023, Azure Linux 3.0, and Oracle Linux 10.2. On Ubuntu, permissions are 0660 root:kvm. The 0666 default means any unprivileged local user can exploit this without group membership. |
| Scanning/exposure | Not remotely exploitable — no Shodan/Censys/GreyNoise exposure surface. The attack surface is local: any Linux system with vhost module loaded and /dev/vhost-* accessible. Nessus plugin ID 342043 available per VulDB. |
| Researcher / discovery | Fourie Zhang (TencentOS Security Team / Tencent Zhuque Lab), discovered with assistance from Corvus AI (Tencent's multi-agent vulnerability discovery system). Timeline: bug identified 2026-07-31, fix merged 2026-08-03, CVE announced 2026-08-21, full LPE verified across five distros 2026-08-24, public disclosure 2026-10-12. |
Sources.
Why this verdict
- Canonical hypervisor component — floor is CRITICAL. The vhost subsystem exists solely to accelerate virtio I/O for KVM/QEMU virtual machines. It is, by definition, a hypervisor component. The VM escape path (guest → host via stale IOTLB + QEMU heap corruption) succeeds under documented conditions (vIOMMU + iommu_platform). On multi-tenant KVM hosts, host compromise = fleet-scale impact across all co-resident guests. Per the deployment-role blast radius rule, the verdict floor for a bug IN a hypervisor subsystem with a demonstrated cross-boundary escape is CRITICAL.
- Role multiplier: Hypervisor hosts (KVM/QEMU). The documented VM escape chain succeeds when virtual IOMMU is enabled. On dedicated KVM hypervisor nodes — which represent ≥10% of the installed base for vhost by design — the blast radius is tenant → host → fleet. A compromised guest gains arbitrary code execution in the host QEMU process, then leverages root on the hypervisor to access all co-resident VMs. This is the canonical worst-case for any virtualization bug.
- Role multiplier: Kubernetes worker nodes. Many Kubernetes deployments load vhost-net for accelerated pod networking (e.g., with DPDK/SR-IOV passthrough). Root on a Kubernetes node means access to kubelet credentials, all pod secrets on that node, and lateral movement to the control plane. Blast radius: host → cluster.
- Role multiplier: General Linux servers. On RHEL 9.8, Amazon Linux 2023, Azure Linux 3.0, and Oracle Linux 10.2, device nodes are 0666 — any unprivileged shell chains to root. On database servers, CI/CD runners, or backup hosts, this turns a low-value initial foothold into a high-value compromise.
- Trivial exploitation eliminates practical AC barrier. The CVSS vector scores AC:L, and the reality is even more favorable to the attacker: the exploit is deterministic, race-free, requires no heap grooming, and works unchanged across a decade of kernels. The public PoC compiles with a single
ccinvocation and runs in under a second. This is not a theoretical primitive — it is a weaponizable tool. - Default permissions eliminate the PR:L barrier on most enterprise distros. CVSS scores PR:L, implying some privilege is needed. In practice, on four of the five tested enterprise distributions,
/dev/vhost-*is world-accessible (0666). Any process that can execute code — a compromised web application, a container escape to the host namespace, a low-privilege SSH session — can immediately trigger the full chain. - Public PoC with detailed write-up collapses attacker effort to near-zero. Tencent Zhuque Lab's Vghost write-up provides the complete exploitation methodology including KASLR bypass technique, arbitrary read/write primitives, and the VM escape chain. The GitHub PoC is a self-contained C file. The gap between 'public PoC' and 'in-the-wild exploitation' is measured in days, not months.
Why not higher?
A 9.0 rather than 10.0 because the vulnerability requires local access — there is no remote exploitation path. An attacker must first obtain a shell on the target host (or control a guest VM for the escape variant). This initial-access requirement is a genuine constraint that prevents mass autonomous exploitation. The VM escape path additionally requires explicit vIOMMU configuration, which is not the QEMU default. These factors cap the score below the maximum.
Why not lower?
The local-access requirement cannot pull the verdict below CRITICAL because the affected component is canonically a hypervisor subsystem and the demonstrated impact includes guest-to-host VM escape on KVM infrastructure. On non-virtualization hosts, the 0666 default permissions on most enterprise distros mean the 'low privilege' prerequisite is effectively zero — any code execution foothold chains to root instantly. The exploit is deterministic and public. Downgrading to HIGH would require evidence that fewer than 10% of systems with vhost loaded serve virtualization or other high-value roles, but vhost's entire purpose is VM I/O acceleration, and the LPE path threatens every Linux server regardless of role.
Crowdsourced verification payload.
Run this script on each target Linux host as any user (no root required). Invoke with: bash check_vghost.sh. The script checks the running kernel version against known-fixed stable branches and inspects vhost device permissions. Exit code 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN.
#!/usr/bin/env bash
# check_vghost.sh — CVE-2026-74580 (Vghost) local detection
# Checks running kernel version and vhost device permissions.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
KERNEL=$(uname -r)
echo "[*] Running kernel: $KERNEL"
# Extract major.minor.patch from kernel version string
parse_version() {
local ver="$1"
# Strip everything after first hyphen for comparison
local base="${ver%%-*}"
local major minor patch
IFS='.' read -r major minor patch <<< "$base"
patch=${patch%%[^0-9]*} # strip trailing non-numeric
echo "$major $minor ${patch:-0}"
}
version_gte() {
local a1 a2 a3 b1 b2 b3
read -r a1 a2 a3 <<< "$(parse_version "$1")"
read -r b1 b2 b3 <<< "$(parse_version "$2")"
if (( a1 > b1 )); then return 0; fi
if (( a1 < b1 )); then return 1; fi
if (( a2 > b2 )); then return 0; fi
if (( a2 < b2 )); then return 1; fi
if (( a3 >= b3 )); then return 0; fi
return 1
}
VULNERABLE=0
PATCHED=0
read -r MAJOR MINOR PATCH <<< "$(parse_version "$KERNEL")"
# Check against fixed stable branches
if (( MAJOR < 4 )) || { (( MAJOR == 4 )) && (( MINOR < 11 )); }; then
echo "[+] Kernel predates vulnerable code (introduced in 4.11). PATCHED"
PATCHED=1
elif (( MAJOR == 5 && MINOR == 10 )); then
if version_gte "$KERNEL" "5.10.265"; then
echo "[+] Fixed in 5.10.265; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 5.10.x < 5.10.265"; VULNERABLE=1
fi
elif (( MAJOR == 5 && MINOR == 15 )); then
if version_gte "$KERNEL" "5.15.216"; then
echo "[+] Fixed in 5.15.216; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 5.15.x < 5.15.216"; VULNERABLE=1
fi
elif (( MAJOR == 6 && MINOR == 1 )); then
if version_gte "$KERNEL" "6.1.183"; then
echo "[+] Fixed in 6.1.183; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 6.1.x < 6.1.183"; VULNERABLE=1
fi
elif (( MAJOR == 6 && MINOR == 6 )); then
if version_gte "$KERNEL" "6.6.152"; then
echo "[+] Fixed in 6.6.152; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 6.6.x < 6.6.152"; VULNERABLE=1
fi
elif (( MAJOR == 6 && MINOR == 12 )); then
if version_gte "$KERNEL" "6.12.104"; then
echo "[+] Fixed in 6.12.104; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 6.12.x < 6.12.104"; VULNERABLE=1
fi
elif (( MAJOR == 6 && MINOR == 18 )); then
if version_gte "$KERNEL" "6.18.45"; then
echo "[+] Fixed in 6.18.45; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 6.18.x < 6.18.45"; VULNERABLE=1
fi
elif (( MAJOR == 7 && MINOR == 1 )); then
if version_gte "$KERNEL" "7.1.9"; then
echo "[+] Fixed in 7.1.9; running $KERNEL. PATCHED"; PATCHED=1
else
echo "[-] Vulnerable: 7.1.x < 7.1.9"; VULNERABLE=1
fi
elif (( MAJOR == 7 && MINOR >= 2 )); then
echo "[+] Kernel 7.2+ includes the fix. PATCHED"; PATCHED=1
elif (( MAJOR >= 4 && MAJOR <= 7 )); then
# Non-stable branches between 4.11 and 7.1 without explicit fix tracking
echo "[?] Kernel $KERNEL is in the vulnerable range (4.11-7.2) but not a tracked stable branch."
echo " Check if your distro has backported commit de845981da67."
fi
# Check vhost device permissions
echo ""
echo "[*] Checking vhost device exposure:"
EXPOSED=0
for dev in /dev/vhost-net /dev/vhost-vsock /dev/vhost-scsi; do
if [ -e "$dev" ]; then
PERMS=$(stat -c '%a' "$dev" 2>/dev/null || stat -f '%Lp' "$dev" 2>/dev/null)
OWNER=$(stat -c '%U:%G' "$dev" 2>/dev/null || stat -f '%Su:%Sg' "$dev" 2>/dev/null)
echo " $dev mode=$PERMS owner=$OWNER"
if [[ "$PERMS" == *"666"* ]] || [[ "$PERMS" == *"662"* ]]; then
echo " WARNING: $dev is world-writable — any local user can exploit CVE-2026-74580"
EXPOSED=1
fi
else
echo " $dev not present"
fi
done
# Check if vhost modules are loaded
echo ""
echo "[*] Checking vhost module status:"
if lsmod 2>/dev/null | grep -q vhost; then
lsmod | grep vhost | while read -r mod rest; do
echo " Module loaded: $mod"
done
else
echo " No vhost modules currently loaded"
fi
echo ""
if (( PATCHED == 1 )); then
echo "RESULT: PATCHED"
exit 0
elif (( VULNERABLE == 1 )); then
if (( EXPOSED == 1 )); then
echo "RESULT: VULNERABLE (world-accessible vhost devices — CRITICAL exposure)"
else
echo "RESULT: VULNERABLE"
fi
exit 1
else
echo "RESULT: UNKNOWN — verify commit de845981da67 is present in your kernel source"
exit 2
fi