In net/ipv4/af_inet.c, readers of inet_opt hold rcu_read_lock and call rcu_dereference. The destructor in the same file calls plain kfree. CVE-2026-98432 is that mismatch, held open since Linux 4.4, closed on 2026-10-05 by a two-line patch that adds kfree_rcu to the two destructors that opted out.
CVE-2026-98432: Two Destructors in net/ipv4 Used kfree(). The Sibling Writers Already Used kfree_rcu().
pattern
cve
proof of concept
- Quaerendir/cve-2026-98432-audit%20(%E2%98%850)
- suominen/CVE-2026-98432%20(%E2%98%850)
- axisops/CVE-2026-98432%20(%E2%98%850)
- nsrg-fmlorg/kpatch-cve-2026-98432%20(%E2%98%850)
- typhoon1217/cve-2026-98432-mitigation%20(%E2%98%850)
- seclists.org/oss-sec/2026/q4/437
- mahdi-salmanzade/CVE-2026-98432%20(%E2%98%850)
- H1z3-br0/CVE-2026-98432%20(%E2%98%850)
- infosec.exchange/@S1m/117528345566911508
- fbuff-tools/cve-2026-98432-checker%20(%E2%98%850)
- bitwire-it/Probe-CVE-2026-98432%20(%E2%98%851)
- scriptzteam/Paranoid-CVE-2026-98432%20(%E2%98%850)
- medandevsec/cve-2026-98432-ubuntu-analisis%20(%E2%98%850)
- polikhronidi/cve-2026-98432-ubuntu-backport%20(%E2%98%850)
- seclists.org/oss-sec/2026/q4/442
- tc4dy/CVE-2026-98432-PoC-Exploit%20(%E2%98%850)
- Alucard0x1/cve-2026-98432%20(%E2%98%850)
- MikkoAbudo/CVE-2026-98432-POC%20(%E2%98%851)
- xen0bit/netprobe-cve-2026-98432%20(%E2%98%850)
- davetha/cve-2026-98432%20(%E2%98%850)
- ZombiePm/cve-2026-98432-mitigation%20(%E2%98%850)
- akamai/cve-2026-98432-validation-mitigation%20(%E2%98%850)
- alvaroguzmancode/cve-2026-98432%20(%E2%98%850)
- brett6320/fix_CVE-2026-98432%20(%E2%98%850)
- infosec.exchange/@cloud/117534018172554423
- tiendungdev/cve-2026-98432-guard%20(%E2%98%850)
- infosec.exchange/@securityfeed/117534978438308575
- ndeet/cve-2026-98432%20(%E2%98%850)
- soroushneshati/cve-2026-98432-ubuntu-mitigation%20(%E2%98%850)
- nfodor/cve-2026-98432-nft-mitigation%20(%E2%98%850)
- infosec.exchange/@cloud/117535945688003810
- antonyantony/cve-2026-98432-nft%20(%E2%98%850)
- sevaepsteyn/cve-2026-98432-ebpf%20(%E2%98%850)
- googlesky/CVE-2026-98432%20(%E2%98%850)
- AronWang001/debian-cve-2026-98432-fix%20(%E2%98%850)
- seclists.org/oss-sec/2026/q4/459
- AronWang001/linux-cve-2026-98432-fix%20(%E2%98%850)
- Ghost-Bx1/cve-2026-98432-linux-tcp-uaf%20(%E2%98%850)
- Mervent/cve-2026-98432%20(%E2%98%850)
- al4n4n/CVE-2026-98432%20(%E2%98%850)
- fetus-hina/cve-2026-98432-mitigation-rpm%20(%E2%98%850)
- illuscapital/CVE-2026-98432%20(%E2%98%850)
- 0xSpuddy/cve-2026-98432-check%20(%E2%98%850)
- xxhjkl/cve-2026-98432-check%20(%E2%98%850)
- johnhsb/linux-tcp-uaf-cve-2026-98432%20(%E2%98%850)
- Omniversetr/omnicheck_CVE-2026-98432%20(%E2%98%850)
- matthew-hollick/mitigate-cve-2026-98432%20(%E2%98%850)
- thiscitze/cve-2026-98432-root-shell%20(%E2%98%850)
- maxottovon/CVE-2026-98432-scan%20(%E2%98%850)
- infosec.exchange/@metapsyche/117547993099213172
- marcelofmatos/cve-2026-98432-check%20(%E2%98%850)
- knneth/cve-2026-98432-dkms%20(%E2%98%850)
- BigBIueWhale/cve-2026-98432-kernel-upgrade%20(%E2%98%850)
- 0xBlackash/CVE-2026-98432%20(%E2%98%850)
- valkenindustries/cve-2026-98432-mitigation%20(%E2%98%850)
- upeul/cve-2026-98432-linux%20(%E2%98%850)
- IgrekLg/cve-2026-98432-mitigation%20(%E2%98%850)
- Pr0fEs0r-X/CVE-2026-98432-Checker-v-1.0-%20(%E2%98%850)
- GarphenGate/cve-2026-98432-defender-toolkit%20(%E2%98%850)
- seclists.org/oss-sec/2026/q4/476
- lowerpower/cve-2026-98432-mitigation%20(%E2%98%850)
- infosec.exchange/@stackwatch/117551714339447109
- infosec.exchange/@DailyCyberSecurity/117551671249270864
- schnied/cve-2026-98432-mitigation-iptables%20(%E2%98%850)
- infosec.exchange/@edwardk/117552705135709407
- mrjoshuap/ansible-cve-2026-98432%20(%E2%98%850)
- luxagen/tester-linux-cve-2026-98432%20(%E2%98%850)
- muhammedemintombak/pardus21-cve-2026-98432%20(%E2%98%850)
- hdp1972be-svg/cve_2026_98432_guard%20(%E2%98%850)
- infosec.exchange/@codingitwrong/117555465046973760
- zenjabba/cve-2026-98432-mitigation%20(%E2%98%850)
- t0ge-kun/CVE-2026-98432-check%20(%E2%98%850)
- t-kishida001/CVE-2026-98432-check%20(%E2%98%850)
- downitch/CVE-2026-98432_poc%20(%E2%98%850)
- infosec.exchange/@stackwatch/117560263076168604
- ScudraServicos/cve-2026-98432-mitigation%20(%E2%98%850)
- cybervenom01/Mitigation_CVE-2026-98432%20(%E2%98%850)
- moatome/CVE-2026-98432-pen-test%20(%E2%98%850)
- moatome/CVE-2026-98432-pen-test-main%20(%E2%98%850)
- Certbn/CVE-2026-98432-Linux-IPv4-TCP-IP-Use-After-Free%20(%E2%98%850)
- INFOKOM-KI/CVE-2026-98432-Wazuh-%20(%E2%98%850)
- datacenter-metrotel/Mitigating-CVE-2026-98432%20(%E2%98%850)
- keithel/ubuntu-26.04-kernel-cve-2026-98432-patch-build-docker%20(%E2%98%850)
- infosec.exchange/@wdormann/117563965646730770
- carlosbustillordguez/cve-2026-98432-mitigation%20(%E2%98%850)
- dolistblesson/CVE-2026-98432-update%20(%E2%98%850)
- sv3t0sl4v/CVE-2026-98432-Ubuntu-Temporary-Mitigation%20(%E2%98%850)
- mafudge/cve-2026-98432%20(%E2%98%850)
- infosec.exchange/@beyondmachines1/117568681168178074
- s97472091-pixel/verification-gap-cve-2026-98432%20(%E2%98%850)
- infosec.exchange/@codingitwrong/117569656084164086
- infosec.exchange/@blueteamsec/117573923794647085
- zhao-xiaogang/cve_2026_98432_livepatch%20(%E2%98%850)
- infosec.exchange/@stackwatch/117576869127306586
- ashrafzaryouh/CVE-2026-98432%20(%E2%98%851)
- makslanies/cve-2026-98432-mitigation%20(%E2%98%850)
- jackykeung/CVE-2026-98432-Verified-Attack%20(%E2%98%850)
- nnssh/CVE-2026-98432_poc%20(%E2%98%850)
- rootagi/CVE-2026-98432%20(%E2%98%850)
- sam00/CVE-2026-98432-POC-Exploit%20(%E2%98%850)
- zake1god/CVE-2026-98432%20(%E2%98%850)
- ylh440104/cve-2026-98432-chain%20(%E2%98%851)
The convention was already in place. In net/ipv4/af_inet.c, functions that read inet->inet_opt hold rcu_read_lock() and use rcu_dereference() to walk the pointer. The destructor in the same file does not. At line 158 of the pre-patch tree, inet_sock_destruct() calls kfree(rcu_dereference_protected(inet->inet_opt, 1)). A second destructor, in the request-socket teardown path, does the same for ireq_opt. Both free the object without waiting for readers to leave. Eric Dumazet's two-line patch on 2026-10-05 added kfree_rcu to both sites. The commit message says what the readers already said: this pointer lives behind an RCU grace period.
The race lives inside a single rcu_read_lock
tcp_v4_syn_recv_sock() promotes a request socket to a child socket. It hands ireq->ireq_opt to the child without copying. The child now owns the allocation. When inet_sock_destruct() runs on that child later, it calls plain kfree() on inet->inet_opt.
Meanwhile, tcp_v4_send_synack() on another CPU holds rcu_read_lock() and walks the same ireq_opt to build a SYN-ACK. The two paths overlap. The reader dereferences freed memory. KASAN sees it. On a production kernel without KASAN, the reader walks whatever object has replaced the slab allocation by the time the TX path reaches it. Most of the time the slab is quiet and the reader walks something that still looks like options. Some of the time it walks something that looks like controlled attacker bytes, and that is the chain.
The fix commit is e3f33b0a1d89d738e2b913dab519226eaf76e15b, dated 2026-10-05. The diff is minimal. kfree becomes kfree_rcu at both sites. CVE-2026-98432 was published 2026-10-15. Debian 13 shipped a build on 2026-10-16. Red Hat's advisory landed 2026-11-01. Ubuntu is still lagging at the time of this post.
The rule is visible in the same file
inet_sk_rebuild_header() is one of the readers. It opens with rcu_read_lock(), calls inet_opt = rcu_dereference(inet->inet_opt), uses the pointer, then unlocks. The reader protocol is explicit and the primitive name says so. inet_sk_reselect_saddr() is another, lower in the same file, which uses rcu_dereference_protected(inet->inet_opt, lockdep_sock_is_held(sk)) because the writer side holds the socket lock. Both document the ownership rules at every call site.
The destructor on line 158 of the same file calls kfree(rcu_dereference_protected(inet->inet_opt, 1)). The second argument says "I know this is a writer context, no lock is needed to dereference." That is true. It is also irrelevant to the question of whether a reader on another CPU still points into the allocation. The destruct protocol is a plain free. That gap is the bug, and it is visible inside a single compilation unit without any cross-file reasoning.
Request sockets have the same shape. The ehash table introduced in commit 079096f103fa in Linux 4.4 holds TCP_NEW_SYN_RECV entries alongside established sockets. Readers on the TX side walk ireq_opt under RCU. The request-socket destructor frees it without one. When a listener accepts a connection and the child inherits ireq_opt without copy, the destructor on the child can free an object that a concurrent SYN-ACK path still reads.
There is a second trigger path introduced later. With net.ipv4.tcp_migrate_req=1, a request socket can be migrated from one listener to another when the original listener closes. The migration touches the same pointer, and under race it hands the window to the attacker without needing listener teardown. BPF_SK_REUSEPORT_SELECT_OR_MIGRATE opens the same door for anything using SO_REUSEPORT groups. Workloads that use reuseport migration for zero-downtime restarts are structurally more exposed to this bug than workloads that do not.
The CVSS numbers reflect the asymmetry of opinion. The kernel CNA assigned 9.8 with AC:L. Red Hat and several downstream vendors assigned 8.1 with AC:H. The attack is remote in both reads. The complexity question is whether the attacker can arrange the race reliably. Xinyang Ge, who reported the bug for Anthropic's Frontier Red Team, says the team built a remote-root MPTCP chain against a stock Debian 13 image on the strength of the race. That claim landed on 2026-10-27 and remains unverified by a public artifact.
MikkoAbudo wrote the race, nothing more
tcp_reqopt_race.c from MikkoAbudo is two thousand lines of C that build raw Ethernet frames, pin the sender to a CPU, fragment the trip so the RX queue splits, then volley dup-SYN against ACK/RST with a skew sweep. It carries IP options in several flavours: Record Route, Timestamp, LSRR, SSRR, and an oversize RR variant it labels BIGRR. The Chinese comments name the mechanism exactly. tcp_v4_syn_recv_sock() hands ireq->ireq_opt to the child. The destructor frees it with plain kfree(). The reader on the TX path dereferences freed memory.
What the file does not include is also legible from reading it. There is no KASLR leak. There is no reclaim primitive. There is no shell. The PoC trips the race. On a KASAN build it reports. On a stock kernel it usually produces nothing visible unless the attacker has already arranged the slab pressure to replace ip_options_rcu with something exploitable, and the PoC does not arrange that.
This is what an honest demonstration of a kernel-memory bug looks like. It shows the race exists. It leaves weaponisation to a different author and a different document.
thiscitze shipped a lab aid and a punch list
cve-2026-98432-root-shell from thiscitze builds Linux 6.12.112 with aid patches, disables KASLR, and then names three things the researcher could not get past.
- The seventy-two-byte
ip_options_rcureclaim does not reliably land onsaved_syn. - Same-type reclaim yields no text pointer leak.
- SSRR, RR, and Timestamp stores give four controlled bytes near the skb buffer, not an arbitrary write.
The README credits Anthropic's team for the only public claim of a working chain, dated 2026-10-27, and notes that the chain's code is not released. The file's own sentence: "A stock-kernel weaponised chain is not publicly available as of 2026-11-02."
This is a defender's document wearing an attacker's filename. It names the blockers the chain would have to solve. It does not solve them. It is more useful than most things on the public list, because it is honest about where the research stops.
Ghost-Bx1 shipped a placeholder PoC calling /proc/kallsyms
cve-2026-98432-linux-tcp-uaf/exploit.c from Ghost-Bx1 is a textbook placeholder PoC. It opens /proc/kallsyms, reads addresses for commit_creds and prepare_kernel_cred, patches a shellcode blob, and calls the result an exploit. Line 141 of the file says, in Portuguese: "Enderecos abaixo sao placeholders - substitua pelos reais." Addresses below are placeholders. Replace with real ones.
Two problems. First, /proc/kallsyms returns zeroed addresses to unprivileged readers on every modern kernel. If the running process can read real values, the process is already root, and nothing else in the file matters. Second, CVE-2026-98432 is a remote bug. The vulnerable code path is reached by sending SYNs with IP options to a listening socket. A local privesc that assumes kallsyms access has not engaged the vulnerability at all. The file ships two separate dishonesties, and together they ship nothing.
The repository is packaged like a weapon. It reads like a tutorial for the wrong vulnerability. This is the shape the placeholder-PoC pattern keeps producing: a CVE-named filename, a shell payload, and one honest comment buried in the middle that says "replace this with the real value," where the real value is either privileged or nonexistent.
Ninety repositories, three exploits, one real
A scan on 2026-11-08 finds roughly ninety public repositories referencing CVE-2026-98432. The distribution is lopsided in a way that is now familiar.
The defensive tier is the bulk of it. There are nftables rules dropping TCP SYNs that carry IP options. One such rule is three lines: a chain on the input hook, a match on ip hdrlength > 5, a drop. There are eBPF filters at XDP. There are ansible playbooks that pin net.ipv4.tcp_syncookies=1 and zero net.ipv4.tcp_migrate_req. There are kernel-installer wrappers. There are audit scripts that read /proc/sys/net/ipv4/tcp_migrate_req and /sys/module/ipv4/parameters. There are three independent repositories named a variant of verification-gap-cve-2026-98432 that collate vendor advisories into one table, where Debian ships on 2026-10-16, Red Hat on 2026-11-01, and Ubuntu lags.
The offensive tier has three. MikkoAbudo trips the race. thiscitze builds the lab and lists the blockers. Ghost-Bx1 ships placeholders. That is the distribution.
Anthropic's post on 2026-10-27 claims a remote-root MPTCP chain built from this bug, against an unmodified Debian 13 image. The code is not public. The claim is unverifiable in the ordinary sense. It is also plausible. Xinyang Ge, who found and reported the bug, works on that team, and the team's incentive is to publish proof of impact. The decision not to release the chain is its own kind of signal, and the signal is not reassurance.
The diff was the whole story
The commit message on e3f33b0a1d89 is six lines long. It notes the two destructors needed a grace period. It describes no exploit. It names no victim. The tone is identical to every other RCU-conversion patch the subsystem has absorbed over the last decade.
The surprise is not the patch. It is that the destructor path shipped without the primitive for long enough that a researcher at a different company found it, filed it, and had time to write a chain. The reader protocol in af_inet.c has been RCU since well before 4.4. The destructor in af_inet.c has been plain-kfree the entire time. Both protocols were visible in the same file. Two destructors opted out of a convention their own file had already written down. The CVE exists because nobody who read that file flagged the mismatch until someone wanted to.
What to do on 2026-11-08
Patch. If the kernel cannot be rebooted today, drop TCP SYNs carrying IP options at the edge. The nftables rule is three lines. The sysctl change is one line. Both have near-zero cost on production workloads, because inbound TCP SYNs with IP options are vanishingly rare outside of research traffic. Also consider zeroing net.ipv4.tcp_migrate_req on any host that does not need reuseport migration, because the migration path is a second trigger that does not require listener teardown.
The ninety-repo signal is not that the bug is overhyped. It is that the ecosystem produces defence faster than it produces offence, and that most of the offence produced in public is either unreliable or unrelated to the stated target. Track the Anthropic post if you track anyone. The rest is fog.
Patch, or drop the traffic. The worm is not in these repositories.