CVE-2024-1086 — Linux kernel nf_tables use-after-free (LPE)
A use-after-free in the netfilter nf_tables subsystem that turns any code execution as an unprivileged user into root. It sat unnoticed in the kernel for nearly a decade, was disclosed in January 2024, and a public PoC dropped two months later. If you ever get an RCE on any of your hosts — through a web app, a container escape, a sandboxed service — this is the bug that closes the deal.
TL;DR
- Use-after-free in
net/netfilter/nf_tables_api.c→ reliable local privilege escalation from unprivileged user to root. - Disclosed 2024-01-31 by Notselwyn; public PoC released in March 2024 and widely weaponised in container escape and post-exploitation chains.
- Affects Linux kernels 3.15 through 6.8-rc1 — i.e. essentially every still-supported distro at disclosure time.
- Fixed in mainline 6.8-rc2 (commit
f342de4e2f33) and backported into stable trees during February–March 2024. - Tracked as actively exploited by CISA; CVSS 7.8 (High, Local).
- Pre-patch mitigations: disable unprivileged user-namespace creation, blocklist the
nf_tablesmodule, or apply a live-patch (Ubuntu Livepatch / Oracle Ksplice).
At a glance
| CVE ID | CVE-2024-1086 |
|---|---|
| Severity | High (CVSS 7.8) · tracked as actively-exploited by CISA |
| CVSS 3.1 score | 7.8 |
| CVSS vector | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-416 (Use After Free) |
| Affected kernel range | 3.15 through 6.8-rc1 |
| Fixed in (mainline) | 6.8-rc2 (commit f342de4e2f33) |
| Public PoC | Exists (Notselwyn, March 2024) — not linked here |
| Mitigation without patch | Disable unprivileged user namespaces, blocklist nf_tables, or live-patch |
| Published | 2024-01-31 |
What goes wrong in nf_tables
Netfilter verdicts (NF_ACCEPT, NF_DROP, NF_STOLEN, …) are small integer return
codes that hooks pass back up the netfilter stack to say what
should happen to a packet. The bug is in nft_verdict_init():
it accepts a positive return value from a user-controlled verdict
that the kernel then treats as if it were NF_DROP or NF_ACCEPT.
When the calling code in nf_hook_slow() sees the (forged) NF_DROP,
it calls kfree_skb() on the packet buffer to clean up — but the
caller further up the stack also still owns a reference to that
same skb and will free it again on its own path out. That
double-free leaves a freshly-freed slab object reachable from a
live kernel pointer: a textbook use-after-free.
The published exploitation strategy sprays the freed slab with attacker-controlled data and reuses the dangling pointer to pivot to arbitrary read/write of kernel memory, then overwrites the current task's credentials to gain root. None of that requires special hardware, no kernel symbols leaked, no ASLR bypass — just an unprivileged user namespace, which most distros enable by default.
Affected kernel versions and fix paths
Per-distro fix lines for the kernels homelab and SMB fleets typically run. Exact stable-update version numbers vary by point release; the table below uses the spring-2024 advisory lines as a coarse guide. Check your distro's security tracker for the precise build that landed on your release.
| Distro / kernel line | Vulnerable | Fixed in |
|---|---|---|
| Linux mainline | 3.15 through 6.8-rc1 | 6.8-rc2 (commit f342de4e2f33) |
| Debian 11 bullseye | linux 5.10.x pre-update | Debian security update, spring 2024 (DSA series) |
| Debian 12 bookworm | linux 6.1.x pre-update | Debian security update, spring 2024 (DSA series) |
| Ubuntu 20.04 focal | linux 5.4 / 5.15 HWE pre-update | USN series, spring 2024 |
| Ubuntu 22.04 jammy | linux 5.15 / 6.5 HWE pre-update | USN series, spring 2024 |
| Ubuntu 24.04 noble | linux 6.8 pre-GA | Fix landed in the initial 24.04 release kernel |
| RHEL 9 / Rocky 9 / AlmaLinux 9 | linux 5.14 RHEL kernel pre-update | RHSA series, spring 2024 |
| RHEL 8 / Rocky 8 / AlmaLinux 8 | linux 4.18 RHEL kernel pre-update | RHSA series, spring 2024 |
Quick scan check
Identify the running kernel and the installed kernel package version, then cross-check against your distro's advisory.
uname -r
# Debian / Ubuntu
apt list --installed 2>/dev/null | grep ^linux-image-
# RHEL family
rpm -qa kernel kernel-core
# Live-patched systems
kpatch list 2>/dev/null || true
# Ubuntu Livepatch status
canonical-livepatch status 2>/dev/null || true
Note that uname -r reflects the running kernel — if a security
update has been installed but the host hasn't rebooted, the
vulnerable kernel is still in memory. Reboot, or apply a
live-patch, to actually close the door.
Mitigations beyond patching
If you can't patch immediately, three controls each break the published exploit path on their own:
-
Disable unprivileged user namespaces.
The exploit needs
CAP_NET_ADMINin a user namespace to reach the buggynft_verdict_init()path. Settingsysctl kernel.unprivileged_userns_clone=0(Debian/Ubuntu) or the equivalentuser.max_user_namespaces=0closes that off, at the cost of breaking rootless containers / Flatpak sandboxing. -
Blocklist the
nf_tablesmodule. Drop a file in/etc/modprobe.d/withinstall nf_tables /bin/trueandblacklist nf_tables. Only viable on hosts that use legacy iptables or no firewall at all — modern distros default to nftables for their firewall. - Apply a live-patch. Ubuntu Livepatch and Oracle Ksplice both shipped a hot-patch for this CVE within days of the public PoC, requiring no reboot.
Why this is the stage-2 multiplier you didn't think about
A lot of homelab and SMB threat modelling stops at "the box only runs a reverse proxy / a Plex server / a Home Assistant instance, and that service is patched". That framing ignores stage 2.
The moment any unprivileged code executes — a web-app RCE, a container escape like CVE-2024-21626, a sandbox break in a browser-rendered service like CVE-2024-47176, a malicious package pulled by a build pipeline — an unpatched kernel LPE turns "compromise of a single service account" into "compromise of the host". That is a categorical jump: from logs you can contain to a rootkit you have to wipe.
This is exactly the reason KEV-listed LPEs deserve patch priority even when your edge is locked down. We unpack that framing further in how to triage CVE findings without losing your weekend and the prioritisation maths in EPSS for the rest of us. For the broader cadence argument see continuous CVE scanning vs patching.
What Noxen does about this
Noxen matches CVE-2024-1086 against the installed kernel
package version on every enrolled host. The package-manifest
probe pulls linux-image-* on Debian/Ubuntu and kernel /
kernel-core on the RHEL family, compares against the per-distro
fix lines from the signed daily feed, and flags any host
running a kernel below the fix line — including the case
where a patched package is installed but the host hasn't
rebooted into it.
Authoritative sources
- NVD entry for CVE-2024-1086
- cve.org record
- FIRST EPSS API for CVE-2024-1086
- CISA KEV catalogue (search for CVE-2024-1086)
See what Noxen does about CVEs like this → More on CVE management →