A kernel priority-inheritance lock trusts the wrong task pointer when the waiter walks out early
rtmutex is the Linux kernel's realtime-friendly mutex, used by futex PI, RCU boost, and every priority-inheritance path. The bug is in remove_waiter(): after a waiter aborts (signal, timeout, pthread_cancel), the cleanup path referenced current instead of waiter::task to walk the top-waiter chain. In a narrow race — where the waiter's task has already begun exit and the pi-chain is being re-boosted from another CPU — the wrong pointer is dereferenced, giving a classic use-after-free on the freed task_struct. A local attacker who can win the race can convert this into an arbitrary write against a freed slab object and land root / kernel-mode execution. The commit Use waiter::task instead of current in remove_waiter() lands in mainline; the fix is being backported to stable trees 5.10.y, 5.15.y, 6.1.y, 6.6.y, and 6.12.y as of the disclosure window.
The vendor HIGH / 7.8 with vector AV:L/AC:L/PR:L/UI:N/C:H/I:H/A:H is the correct shape for a kernel LPE, but the AC:L is generous — hitting the pi-chain race reliably requires CPU pinning, adversarial scheduling, and usually a heap-spray primitive against task_struct slab. Reality tracks vendor severity: it is a real local privilege escalation on any Linux host where an unprivileged attacker can execute code, which includes multi-tenant Kubernetes nodes, shared bastions, CI runners, and any hosting/PaaS box. We hold at HIGH.
5 steps from start to impact.
Attacker lands unprivileged code execution on the host
AV:L by design.- Existing unprivileged code execution on the target Linux host
- Kernel built with
CONFIG_RT_MUTEXES=y(default in every distro kernel)
- Rules out purely-remote actors — attacker must have already breached perimeter or hold a valid account
- Locked-down container runtimes (
gVisor,Kata, seccomp default profiles) blunt syscall reach but do not eliminate futex
Trigger the rtmutex pi-chain race via futex PI
PTHREAD_PRIO_INHERIT mutex, with a third thread cancelled mid-acquire. The classic weaponization pattern is derived from exploit-db futex-race exploits — CPU-pin threads to force the boost path and issue pthread_cancel() (or deliver SIGKILL) at the exact moment the boosted waiter enters remove_waiter().futex(2)syscall available (not blocked by seccomp)- Ability to set CPU affinity or run enough threads to hit the window
- Race is narrow — typical win rate <1% per attempt on modern schedulers
- seccomp-bpf profiles that drop
sched_setaffinityreduce reliability sharply kernel.unprivileged_userns_clone=0blunts some heap-shaping tricks
SYSCALL rules on sched_setaffinity+futex bursts flag it if configured; default installs won'tGroom the kmalloc-cg / task_struct slab for the UAF
task_struct (or a same-slab object under CONFIG_KMALLOC_SPLIT_VARSIZE) must be reclaimed by attacker-controlled data. Standard technique is spraying via msgsnd, sendmsg, setxattr, or io_uring sqe rings — DirtyCred / CVE-2022-2588-style primitives apply.- Access to a spray primitive not blocked by seccomp
- Predictable slab allocator behavior —
SLUBwithslab_nomergeoff helps the attacker
CONFIG_SLAB_FREELIST_RANDOM+CONFIG_SLAB_FREELIST_HARDENED(defaults on RHEL 9, Ubuntu 22.04+) drop reliability by ~10xCONFIG_RANDOM_KMALLOC_CACHES(6.6+) further isolates victim objectskernel.dmesg_restrict=1hides the crash telemetry attackers use to iterate
general protection fault shows up in dmesg and gets shipped by journald → SIEM if you collect itOverwrite creds / modprobe_path → root
cred->uid/gid on their own task (the DirtyCred pattern) or corrupts a kernel function pointer (e.g., modprobe_path) to run an attacker binary as root. Result: UID 0 with full capabilities and namespace escape from most container runtimes.- Successful reclaim in step 3
- KASLR leak or a target that does not require an absolute pointer (creds overwrite does not)
CONFIG_STATIC_USERMODEHELPER(rare) neutersmodprobe_path- SELinux/AppArmor in enforcing mode restricts what root can do next, but does not stop the escalation itself
setuid(0) from unexpected parents; EDR credential-theft heuristics catch post-root behavior, not the primitiveEscape container / pivot on the node
/var/lib/kubelet, reads every pod's secrets, or on a hypervisor touches other tenants' guest memory. This is the blast-radius amplifier that keeps the verdict at HIGH.- Affected host is a shared-tenancy node (K8s worker, KVM host, CI runner, bastion)
- Single-tenant workstations and dedicated appliance hosts see local root only — no lateral bonus
kubelet credential use from unexpected pods) and CSPM toolsThe supporting signals.
| In-the-wild status | No known exploitation. Not on CISA KEV as of 2026-07-08. No campaign attribution. |
|---|---|
| Public PoC | None public. Commit message and syzbot-adjacent race analysis published, but no weaponized exploit repo on GitHub or exploit-db at time of writing. |
| EPSS | 0.00125 (~0.1%) — bottom-decile percentile; the model sees no signal of coming exploitation. |
| KEV | Not listed. No CISA due-date. |
| CVSS 3.1 | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = 7.8 HIGH. AC:L is optimistic given the pi-chain race; S:U understates the container-escape amplifier. |
| CWE | CWE-416 — Use-After-Free on task_struct via stale current reference in remove_waiter(). |
| Affected versions | All maintained Linux stable branches prior to the backport: 5.4.y, 5.10.y, 5.15.y, 6.1.y, 6.6.y, 6.12.y — anything with CONFIG_RT_MUTEXES=y (i.e., every distro kernel). |
| Fixed versions | Mainline commit rtmutex: Use waiter::task instead of current in remove_waiter() — landing in stable point releases; distro backports rolling out via RHSA/USN/DSA/openSUSE-SU channels. |
| Exposure data | Not internet-reachable by definition (AV:L). Shodan/Censys/GreyNoise irrelevant. Real exposure is the installed base of Linux hosts with unprivileged local users — effectively every K8s node, CI runner, and shared bastion in the fleet. |
| Disclosed | 2026-05-21 by upstream Linux kernel maintainers. |
noisgate verdict.
Kernel-mode use-after-free reachable from any unprivileged local context — the affected code is compiled into every mainstream Linux distribution kernel, so the installed base at high-value roles (K8s workers, KVM hosts, CI runners, multi-tenant bastions) is effectively 100%. The single decisive factor is deployment-role blast radius on shared-tenancy hosts, which floors the verdict at HIGH even without public exploit code.
Why this verdict
- Baseline is fair: vendor 7.8 HIGH matches the shape of a kernel LPE via UAF — the vector is right and
C:H/I:H/A:Hon kernel mode is not overstated. - Friction adjustment 1 (−0.2): the pi-chain race is narrow and modern slab hardening (
SLAB_FREELIST_RANDOM,RANDOM_KMALLOC_CACHES) cuts exploit reliability substantially — reflected in the 0.00125 EPSS. - Friction adjustment 2 (−0.2): no public PoC and no KEV listing as of 2026-07-08 — nation-state and commodity ransomware crews have not weaponized it yet.
- Role multiplier — shared-tenancy Linux hosts (Kubernetes workers, KVM hypervisors, CI runners, multi-tenant bastions): the documented chain succeeds, and outcome is container escape → node compromise → tenant secrets → cluster-wide pivot. This role is >>10% of enterprise Linux installs by definition, so the verdict floor is HIGH and friction cannot pull it below.
- Role multiplier — single-tenant appliance/workstation Linux: chain succeeds but blast radius stops at the local host; this alone would justify MEDIUM, but the fleet is mixed and you patch the kernel, not the deployment pattern.
Why not higher?
No CRITICAL because there is no remote vector, no wormable path, no KEV listing, and no public exploit. Reliability against hardened distro kernels is meaningfully below 100% — the race window is small and slab randomization forces multiple attempts. CRITICAL is reserved for kernel bugs with weaponized PoCs (Dirty Pipe, DirtyCred) or remote reach.
Why not lower?
Not MEDIUM because kernel LPE on a shared-tenancy Linux host is fleet-scale — one unprivileged foothold on a K8s worker becomes cluster compromise. Every Linux install ships the vulnerable code, and 'requires local access' is trivially satisfied on any host that runs untrusted workloads, CI jobs, or multi-user shells. The role multiplier floors this at HIGH.
What to do — in priority order.
- Deploy distro kernel backport as it lands — Track RHSA / USN / DSA / openSUSE-SU feeds for the
rtmutexbackport and roll via your standard kernel-livepatch or reboot cadence. Per the noisgate mitigation SLA for HIGH, get this into production within 30 days; per the noisgate remediation SLA, complete the fleet within 180 days. - Enable kernel livepatch where available — Ubuntu Livepatch, Oracle Ksplice, SUSE kGraft, and RHEL kpatch can deliver the fix without reboot on the highest-value nodes (K8s control-plane workers, hypervisors). Livepatch first on shared-tenancy hosts within the 30-day mitigation window, then follow with a rebooted kernel for durability.
- Tighten seccomp on untrusted workloads — Kubernetes Pod Security Standard
restricted(default seccompRuntimeDefault) blockssched_setaffinityand other reliability-boosting syscalls the exploit needs. Apply to every namespace running third-party or user-submitted code within the 30-day window. - Enable kernel hardening if not already on — Verify
CONFIG_SLAB_FREELIST_RANDOM=y,CONFIG_SLAB_FREELIST_HARDENED=y, and (6.6+)CONFIG_RANDOM_KMALLOC_CACHES=yare set. Setkernel.dmesg_restrict=1,kernel.kptr_restrict=2, andkernel.unprivileged_userns_clone=0on multi-tenant nodes. Ship via your baseline Ansible/Chef/Salt role. - Alert on kernel oopses from SIEM — Forward
journald/dmesgkernelgeneral protection faultandBUG:lines to SIEM. During an exploit iteration campaign the attacker will crash the kernel several times before landing — this is your loudest signal. Deploy the rule within the 30-day mitigation window.
- Perimeter firewalls / WAF — vector is
AV:L; nothing at L3/L7 touches this. - MFA and SSO hardening — attacker is already an authenticated local user by the time the chain starts.
- Disabling futex — you cannot; glibc pthreads depend on it and half your userland will break.
- AV signatures — the exploit is legitimate
futex()andpthread_cancel()syscall sequences; there is nothing to signature on the primitive itself.
Crowdsourced verification payload.
Run on each Linux target host as root (needs to read /proc/version and the distro package DB). Invoke as sudo bash check-cve-2026-43499.sh. Exits 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN. Ship via your config-management tool and roll the return code into your patch-compliance dashboard.
#!/usr/bin/env bash
# check-cve-2026-43499.sh
# Detects whether the running Linux kernel has the rtmutex remove_waiter() UAF fix.
# Output: VULNERABLE / PATCHED / UNKNOWN
set -u
KREL="$(uname -r)"
OS_ID="$( . /etc/os-release 2>/dev/null; echo "${ID:-unknown}" )"
# Minimum fixed kernel versions per stable branch (adjust as distro backports land).
# Format: "branch_prefix:min_fixed_version"
declare -A FIXED=(
["5.4"]="5.4.290"
["5.10"]="5.10.234"
["5.15"]="5.15.177"
["6.1"]="6.1.128"
["6.6"]="6.6.75"
["6.12"]="6.12.15"
)
verlte() {
# returns 0 if $1 <= $2
[ "$1" = "$(printf '%s\n%s' "$1" "$2" | sort -V | head -n1)" ]
}
branch="$(echo "$KREL" | awk -F. '{print $1"."$2}')"
numeric="$(echo "$KREL" | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/')"
if [ -z "${FIXED[$branch]:-}" ]; then
echo "UNKNOWN: kernel branch $branch not in fixed-version table (running $KREL on $OS_ID)"
exit 2
fi
min_fixed="${FIXED[$branch]}"
if verlte "$min_fixed" "$numeric"; then
echo "PATCHED: kernel $KREL >= $min_fixed on $OS_ID"
exit 0
else
# Vendor may have backported the fix without bumping SUBLEVEL — check distro changelog.
if command -v rpm >/dev/null 2>&1; then
if rpm -q --changelog kernel 2>/dev/null | grep -qi 'rtmutex.*remove_waiter\|CVE-2026-43499'; then
echo "PATCHED: distro backport detected in rpm changelog ($KREL on $OS_ID)"
exit 0
fi
elif command -v dpkg >/dev/null 2>&1; then
pkg="$(dpkg -l 'linux-image-*' 2>/dev/null | awk '/^ii/{print $2}' | head -n1)"
if [ -n "$pkg" ] && zcat "/usr/share/doc/$pkg/changelog.Debian.gz" 2>/dev/null | grep -qi 'rtmutex.*remove_waiter\|CVE-2026-43499'; then
echo "PATCHED: distro backport detected in dpkg changelog ($KREL on $OS_ID)"
exit 0
fi
fi
echo "VULNERABLE: kernel $KREL on $OS_ID is below fixed $min_fixed and no backport marker found"
exit 1
fi
If you remember one thing.
RuntimeDefault seccomp on every untrusted-workload namespace; and verify the slab-hardening CONFIG_* flags are set on your baseline image. Per the noisgate remediation SLA for HIGH: complete rebooted-kernel deployment across the full Linux fleet within 180 days, prioritized by exposure to unprivileged users. If you see kernel general protection fault bursts in SIEM before then, promote to immediate patch and hunt for the local foothold that triggered them.Sources
- Linux kernel source — kernel/locking/rtmutex.c
- CVE-2026-43499 — NVD
- CWE-416: Use After Free
- CISA KEV catalog
- FIRST EPSS
- Kernel Self Protection Project — slab hardening
- DirtyCred technique (Zhenpeng Lin, USENIX 2022) — task_struct cred-overwrite pattern
- Kubernetes Pod Security Standards — restricted profile
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.