The newest nftables LPE: a use-after-free in the nf_tables transaction-
abort path. An inverted condition (a stray '!') in
nft_map_catchall_activate() makes the abort path process active catch-all
map elements instead of skipping them; a catch-all GOTO element drives a
chain's use-count to zero so a following DELCHAIN frees it while the
catch-all verdict still references it -> UAF, escalatable from an
unprivileged user (userns + nftables) via modprobe_path/selinux_state ROP.
Fixed upstream by f41c5d1; CWE-416, CVSS 7.8; not in CISA KEV. Public
reproduction by FuzzingLabs.
Takes the corpus to 43 modules / 38 CVEs.
🟡 reconstructed trigger, primitive-only, NOT VM-verified — same contract
as nf_tables (CVE-2024-1086). detect() version-gates (catch-all elems
~5.13; Debian backports 6.1.164/6.12.73/6.18.10, 7.0+ inherits) AND
requires unprivileged user_ns clone (else PRECOND_FAIL). exploit() forks
an isolated child, builds a verdict map with a catch-all GOTO element,
provokes an aborting batch to drive the abort-path UAF, observes slabinfo,
and returns EXPLOIT_FAIL — the per-kernel leak + R/W + modprobe_path ROP
is not bundled. kernel_range table verified drift-clean against the live
Debian tracker (the 6.18 branch / 6.18.10 fix is the real forky/sid
backport; the earlier 7.0.10 figure was wrong).
Wired: registry, Makefile, safety rank (35), 6 detect() test rows (version
+ userns gating), CVE_METADATA.json + cve_metadata.c + KEV_CROSSREF.md
(sorted insert, CWE-416/T1068/not-KEV), README + CVES.md + website counts
(43/38) + yellow pill, RELEASE_NOTES v0.9.11, verify-vm target. Credit:
FuzzingLabs + upstream fix f41c5d1. Version 0.9.11.
2.6 KiB
nft_catchall — CVE-2026-23111
An nf_tables use-after-free reachable from an unprivileged user: an
inverted condition in nft_map_catchall_activate() mishandles catch-all
map elements on transaction abort, freeing a chain that a catch-all GOTO
verdict still references.
The bug
nftables maps can hold a catch-all element — a default that matches
when no other element does — and in a verdict map that element carries a
GOTO/JUMP to a chain. nft_map_catchall_activate() runs during the
abort phase of a netlink transaction to re-activate elements that a
rolled-back batch had touched. A single inverted ! makes it operate on
active catch-all elements instead of skipping them, so the referenced
chain's use-count is driven to zero; a subsequent DELCHAIN frees the
chain while the catch-all verdict still points at it → use-after-free.
Chaining a kernel-address leak, arbitrary R/W, and a ROP over
modprobe_path / selinux_state turns the UAF into root — all reachable
by an unprivileged user who has CONFIG_USER_NS to gain CAP_NET_ADMIN
over a private network namespace.
Affected range
| Vulnerable path introduced | ~5.13 (catch-all set elements) |
| Fixed upstream | commit f41c5d1… (remove the inverted !) |
| Debian backports | 6.1.164 (bookworm) · 6.12.73 (trixie) · 6.18.10 (forky·sid) |
| Table thresholds | 6.1.164 · 6.12.73 · 6.18.10 (≤ Debian → drift-clean) |
| NVD class | CWE-416 (Use After Free), CVSS 7.8 |
| CISA KEV | no |
The 5.10 (bullseye) branch is still unfixed at time of writing → version-only VULNERABLE there.
Trigger / detection
detect() returns OK below ~5.13 or for patched kernels, PRECOND_FAIL
when the kernel is vulnerable but unprivileged user-namespace clone is
denied (exploit unreachable), and VULNERABLE when the version is in
range and userns is allowed.
exploit() forks an isolated child that enters unshare(USER|NET), opens
NETLINK_NETFILTER, builds a verdict map with a catch-all GOTO element,
and sends an aborting batch to drive the abort-path UAF; it observes
nft_chain / kmalloc-cg-256 slabinfo and returns EXPLOIT_FAIL
(primitive-only). The full leak + R/W + ROP root-pop is not bundled,
and the trigger is reconstructed from public analysis, not VM-verified.
Fix / mitigation
Upgrade the kernel. As a host hardening stopgap, deny unprivileged
user-namespace clone (sysctl kernel.unprivileged_userns_clone=0, or the
AppArmor apparmor_restrict_unprivileged_userns toggle) — that closes the
unprivileged path even on a kernel-vulnerable host.
Credit
Upstream fix f41c5d1…; public reproduction by FuzzingLabs. See
NOTICE.md.