A janitor who throws away the wrong set of keys, letting anyone who finds them walk into the vault
CVE-2026-43502 is a use-after-free in the Linux kernel's net/rds (Reliable Datagram Sockets) subsystem. When a zerocopy send fails after user pages have been pinned but *before* the message is attached to the sending socket, the purge path misidentifies the page ownership. It cleans up pinned zerocopy pages as if they were normal payload pages, freeing memory the kernel still references. An unprivileged local user can trigger this race to corrupt kernel memory and escalate to root. The bug was introduced in Linux 4.17 (February 2018) and affects every kernel up through pre-7.1-rc3 — an eight-year window. Fixed versions include mainline 7.1-rc3, Ubuntu 6.8.0-136.136 (noble), 5.15.0-186.196 (jammy), and 7.0.0-28.28 (plucky).
The vendor score of HIGH / 7.8 is accurate and needs no adjustment. The attack is local-only (AV:L) which caps remote risk, but three factors keep it firmly HIGH: (1) a polished public PoC ('ZcopyReaper' by NebuSec) removes the exploit-development barrier, (2) the RDS kernel module can be auto-loaded by an unprivileged user via socket(AF_RDS, ...) on default configurations of many distros unless kernel.modules_disabled or module blocklisting is in effect, and (3) the affected version range spans virtually every production kernel shipped in the last eight years. The vendor got this one right.
5 steps from start to impact.
Local unprivileged shell obtained
- Local user account on the target host
- Shell or code execution ability
- Requires prior initial access — this is a post-compromise chain
- Container runtimes with seccomp profiles may block
socket(AF_RDS, ...)syscall
Trigger RDS module auto-load
socket(AF_RDS, SOCK_SEQPACKET, 0) which triggers the kernel's module auto-loader to load rds.ko if not already present. On default installs of RHEL, Ubuntu, SUSE, and Debian the module ships in the kernel package and auto-load is permitted for unprivileged users.- RDS module available in
/lib/modules/ - Module auto-loading not disabled (
kernel.modules_disabled=0) - No module blocklist entry for
rds
- Hardened hosts with
install rds /bin/truein modprobe.d block this - Container runtimes sharing the host kernel typically restrict module loading
- Cloud VMs (AWS, GCP, Azure) on custom kernels may not ship
rds.ko
init_module / finit_module syscalls; Falco rule for unexpected module loads.Race the zerocopy send path
sendmsg() with pinned user pages, then forces a failure *after* page pinning but *before* the message is queued to the socket. The purge path misidentifies page ownership and frees the pinned pages while kernel references remain live.- RDS module loaded (step 2)
- Ability to call
sendmsg()withMSG_ZEROCOPY
- Race window is tight; PoC reliability varies by kernel version and CPU count
- KASAN-enabled debug kernels will detect the UAF and panic rather than allow exploitation
Corrupt kernel heap for privilege escalation
sendmsg on other sockets or add_key syscall). The attacker overwrites a kernel object (such as struct cred or a function pointer) to gain root privileges. The ZcopyReaper PoC demonstrated this on openSUSE 6.4.0-150600.23.100.- Successful race from step 3
- Predictable heap layout (SLUB allocator behavior)
- KASLR adds entropy to kernel addresses; requires info leak or brute force on some configs
- CONFIG_SLAB_FREELIST_HARDENED and CONFIG_SLAB_FREELIST_RANDOM reduce spray reliability
commit_creds() from unexpected call path; kernel integrity monitoring.Root shell — full host compromise
/etc/shadow, install persistence (cron, systemd unit, kernel module), pivot laterally, or exfiltrate data. On a hypervisor or container host, this means control of all guest workloads.- Successful heap corruption from step 4
- SELinux / AppArmor in enforcing mode constrains what even root can do
- Immutable infrastructure (read-only root FS) limits persistence options
ANOM_ROOT_TRANS events.install rds /bin/true to /etc/modprobe.d/disable-rds.conf and run rmmod rds on hosts where it is loaded but not needed. This eliminates the attack surface entirely. Deploy within 30 days per noisgate mitigation SLA for HIGH. Most enterprise environments do not use RDS (it is Oracle RAC and HPC-specific).kernel.modules_disabled=1 after boot or use SELinux/AppArmor to deny sys_module capability to unprivileged processes. This prevents step 2 of the attack chain. Audit with sysctl kernel.modules_disabled.CONFIG_SLAB_FREELIST_HARDENED, CONFIG_SLAB_FREELIST_RANDOM, and KASAN (in test environments) are active. These degrade heap spray reliability and make exploitation significantly harder.socket(AF_RDS, ...). The default Docker seccomp profile does NOT block AF_RDS — you need a custom profile. This protects container-to-host escape paths.- Network firewalls / WAFs — This is a local kernel vulnerability, not a network service. No amount of network filtering prevents exploitation once an attacker has local access.
- Disabling unprivileged user namespaces — NebuSec explicitly confirmed this does not mitigate CVE-2026-43502. The exploit does not depend on user namespaces.
- KASLR alone — While KASLR adds difficulty, kernel address leaks are abundant (e.g., via
/proc/kallsymsif readable, dmesg, or side channels). It is a speed bump, not a mitigation.
The supporting signals.
| In-the-Wild Exploitation | Not confirmed. No reports from CISA KEV, Mandiant, or CrowdStrike as of 2026-09-08. |
|---|---|
| Proof-of-Concept | Public. 'ZcopyReaper' by NebuSec. Demonstrated on openSUSE kernel 6.4.0-150600.23.100. |
| EPSS Score | 0.00123 (≈ top 30% — low probability of exploitation in next 30 days) |
| KEV Status | Not listed as of 2026-09-08 |
| CVSS Vector | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — Local access, low complexity, low privilege, no user interaction. Full CIA impact, scope unchanged. |
| Affected Versions | Linux kernel 4.17 (commit 0cebaccef3ac, Feb 2018) through pre-7.1-rc3 (May 2026). Eight-year window covering virtually all production kernels. |
| Fixed Versions | Mainline 7.1-rc3. Ubuntu: 7.0.0-28.28 (plucky), 6.8.0-136.136 (noble), 5.15.0-186.196 (jammy). RHEL/SUSE backports expected; check distro advisories. |
| Scanning / Exposure | RDS is a local kernel module, not a network-exposed service. Shodan/Censys/GreyNoise have no relevance. Exposure is determined by whether rds.ko ships in the installed kernel package and module auto-load is permitted. |
| Disclosure Date | 2026-05-21 (upstream patch merged) |
| Researcher / Org | NebuSec security research team |
Sources.
Why this verdict
- Public PoC removes exploit barrier: The ZcopyReaper PoC from NebuSec is published and demonstrated on a current enterprise kernel. This shifts the threat from theoretical to script-kiddie accessible for anyone with local access.
- RDS auto-load broadens the target surface: On default RHEL, Ubuntu, SUSE, and Debian installs, an unprivileged user can call
socket(AF_RDS, ...)to auto-loadrds.ko, making the vulnerable code reachable even on hosts that never intentionally use RDS. This neutralizes the 'niche module' downgrade argument. - Eight-year affected range: Kernels from 4.17 (2018) to 7.1-rc3 (2026) are vulnerable. In a 10,000-host fleet, the vast majority of Linux hosts will be running a kernel in this range until patched.
- Role multiplier: This is a *kernel* vulnerability. On hypervisor hosts (KVM), root compromise means control of all guest VMs — blast radius is fleet-scale. On container orchestration nodes (Kubernetes worker/control-plane), root on the host compromises all pods. On CI/CD build servers, root enables supply-chain poisoning. On database servers, root means unrestricted data access. Because the kernel is the affected component, ≥90% of installs are definitionally in a role where LPE to root has HIGH+ blast radius. The floor is HIGH.
- Local-only caps at HIGH: AV:L means the attacker must already have a foothold. This is a post-initial-access privilege escalation, not a remote entry point. This single friction point prevents CRITICAL.
Why not higher?
A CRITICAL rating would require either remote exploitability or active in-the-wild exploitation. CVE-2026-43502 is strictly local (AV:L) — the attacker must already have an unprivileged shell on the target. There is no KEV listing and no confirmed campaigns. While the blast radius on high-value roles is severe, the prerequisite of prior access is a meaningful gate that separates this from CRITICAL-tier vulnerabilities like Zerologon or MOVEit.
Why not lower?
Downgrading below HIGH would require the module to be unreachable or the PoC to be unreliable. Neither is the case: RDS auto-loads on default distro configs, the PoC is public and demonstrated, and the affected kernel range spans eight years of production releases. The kernel is the most privileged component on any host — LPE to root is never MEDIUM when a working exploit exists and the module is reachable without admin help.
Crowdsourced verification payload.
Run this script as root on each target Linux host. It checks whether the running kernel is in the affected range and whether the RDS module is loadable. Example: sudo bash check_cve_2026_43502.sh
#!/bin/bash\n# check_cve_2026_43502.sh — CVE-2026-43502 (ZcopyReaper) detection\n# Run as root on each Linux host.\n# Exit codes: 0=VULNERABLE, 1=PATCHED, 2=UNKNOWN\n\nset -euo pipefail\n\nKVER=$(uname -r)\necho "[*] Running kernel: $KVER"\n\n# Check for known-patched distro kernels (Ubuntu examples)\nPATCHED=0\ncase "$KVER" in\n 7.0.0-28.28*|6.8.0-13[6-9].*|6.8.0-1[4-9][0-9].*|5.15.0-18[6-9].*|5.15.0-19[0-9].*|5.15.0-2[0-9][0-9].*)\n PATCHED=1\n ;;\nesac\n\n# Check mainline version\nMAJOR=$(echo "$KVER" | cut -d. -f1)\nMINOR=$(echo "$KVER" | cut -d. -f2)\nif [ "$MAJOR" -gt 7 ] 2>/dev/null; then\n PATCHED=1\nelif [ "$MAJOR" -eq 7 ] && [ "$MINOR" -ge 1 ] 2>/dev/null; then\n PATCHED=1\nfi\n\nif [ "$PATCHED" -eq 1 ]; then\n echo "[+] PATCHED — kernel $KVER is at or above the fix level."\n exit 1\nfi\n\n# Check if RDS module is loaded or loadable\nRDS_LOADED=0\nif lsmod | grep -q '^rds '; then\n RDS_LOADED=1\n echo "[!] RDS module is currently LOADED."\nfi\n\nRDS_AVAILABLE=0\nif modinfo rds &>/dev/null; then\n RDS_AVAILABLE=1\n echo "[!] RDS module is available for auto-loading."\nfi\n\n# Check blocklist\nRDS_BLOCKED=0\nif grep -rqs 'install rds /bin/true\|install rds /bin/false\|blacklist rds' /etc/modprobe.d/ 2>/dev/null; then\n RDS_BLOCKED=1\n echo "[*] RDS module is blocklisted in modprobe.d."\nfi\n\nif [ "$MAJOR" -lt 4 ] || { [ "$MAJOR" -eq 4 ] && [ "$MINOR" -lt 17 ]; }; then\n echo "[+] PATCHED — kernel $KVER predates the vulnerable commit (4.17)."\n exit 1\nfi\n\nif [ "$RDS_AVAILABLE" -eq 0 ] && [ "$RDS_LOADED" -eq 0 ]; then\n echo "[*] UNKNOWN — kernel is in affected range but rds.ko not found. Likely not vulnerable."\n exit 2\nfi\n\nif [ "$RDS_BLOCKED" -eq 1 ] && [ "$RDS_LOADED" -eq 0 ]; then\n echo "[*] VULNERABLE (mitigated) — kernel in range, RDS blocklisted but not patched."\n echo "VULNERABLE"\n exit 0\nfi\n\necho "[!] VULNERABLE — kernel $KVER is in range 4.17–7.1-rc2 and RDS module is reachable."\necho "VULNERABLE"\nexit 0