Files
SKELETONKEY/modules/nft_catchall_cve_2026_23111/MODULE.md
T
KaraZajac 4d0a0e2443
release / build (arm64) (push) Has been cancelled
release / build (x86_64) (push) Has been cancelled
release / build (x86_64-static / musl) (push) Has been cancelled
release / build (arm64-static / musl) (push) Has been cancelled
release / release (push) Has been cancelled
modules: add nft_catchall (CVE-2026-23111, nf_tables catch-all abort UAF)
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.
2026-06-08 17:42:19 -04:00

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.