CVE-2026-98432 is a use-after-free in the kernel code that sets up incoming IPv4 TCP connections. Every kernel from 4.4 on carries it. This post covers what to run on a server, what each vendor has shipped, and how the bug works. It contains no exploit and no proof of concept.
Vendor status below was read on November 1 and 2, 2026. It changes daily, so treat the trackers as the current answer.
Check a server in three steps
Look at the kernel on the host. Containers share it, so rebuilding an image changes nothing.
uname -r
Compare that with your distribution’s fixed package, because upstream version numbers only apply if you build your own kernel. On Debian:
apt-cache policy linux-image-amd64
After installing a fixed kernel, reboot and run uname -r again. A kernel that is installed but not booted protects nothing.
Fix status
Upstream stable releases with the fix: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10 and 7.3.
| Distribution | Status when checked |
|---|---|
| Debian 12 | Fixed: linux 6.1.190-1 (DLA-4841-1), linux-6.12 6.12.113-1~deb12u1 (DLA-4850-1) |
| Debian 13 | Fixed: 6.12.113-1 (DSA-6568-1) |
| Amazon Linux 2, 2023 | Fixed on all kernels. AL2023 instances locked to a release need 2023.12.20261102 or later |
| Oracle Linux 7 to 10 | UEK fixed on October 16. No fix listed for the Red Hat compatible kernel |
| SUSE | SLES 16, SLES 15 SP4 to SP6 LTSS, SLE Micro 5.3 to 5.5, SL Micro 6.2 and openSUSE Leap 16 fixed. SLES 15 SP7 in progress. Leap 15 and SLES 12 SP5 affected, no fix listed |
| Ubuntu | 22.04, 24.04, 26.04, 26.10: vulnerable, work in progress. 16.04, 18.04, 20.04: vulnerable. 14.04: not affected |
| RHEL 8, 9, 10, OpenShift | Rated critical, fixes being expedited, no fixed kernels listed in the bulletin |
| AlmaLinux | Patched kernels in the testing repository |
| Rocky Linux | CIQ lists fixed builds for some of its own variants. I found no published fix for the community releases |
| Arch | Current package 7.2.14, past the fixed 7.2.10 |
For managed services:
| Service | Status when checked |
|---|---|
| AWS Lambda | Not affected |
| Amazon EKS | AMI release v20261031 or later. Existing nodes need replacing |
| AWS Fargate | Tasks launched after November 1, 17:00 UTC are patched. Older tasks need replacing or retire on their schedule |
| Bottlerocket | Kernel released, AMIs expected from November 2 |
| GKE, AKS | No mention of this CVE in their bulletins |
Debian: which metapackage you have matters
On Bookworm, linux-image-amd64 follows the 6.1 kernel and is at the fixed 6.1.190-1. A machine that was moved to the 6.12 backport won’t be taken along by it. That line has its own metapackage:
sudo apt install linux-image-6.12-amd64
It depends on linux-image-6.12.113+deb12-amd64, the fixed build.
If there is no fix yet
Red Hat publishes an nftables table that drops incoming IPv4 TCP packets carrying IP options. By Red Hat’s own description this lowers the risk without closing it. Try it outside production first, since some workloads may break.
table inet cve_2026_98432 {
chain input {
type filter hook input priority -310; policy accept;
ip protocol tcp ip hdrlength > 5 counter drop
}
}cve-2026-98432.nft
sudo nft --check --file cve-2026-98432.nft
sudo nft --file cve-2026-98432.nft
sudo nft list table inet cve_2026_98432
The counter shows whether the rule is dropping anything, which is useful for finding out if your traffic ever used IP options. AlmaLinux notes that a rule like this does not survive a reboot.
Be careful with GitHub repositories that claim to hold a proof of concept. Atlas Security’s advice is to assume an unvetted one is hostile.
Finding multipath TCP listeners
The exploit Anthropic describes depends on a multipath TCP listener, and you may have one without asking for it: according to the Go team’s oss-security post, listening sockets in Go programs have used multipath TCP by default since Go 1.24.
The obvious check can give a wrong answer. On an Ubuntu cloud image, this came back empty:
ss -Mlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Processoutput
The kernel disagreed:
grep -E '^(protocol|MPTCP)' /proc/net/protocols | cut -c1-24
protocol size sockets
MPTCPv6 2096 0
MPTCP 1936 1output
ss needs the mptcp_diag module, and on this image it lives in an extra package. With that installed, and with root so ss can name the process, the listener appears:
sudo apt install linux-modules-extra-$(uname -r)
sudo ss -Mlnp | awk '{print $1, $4, $6}'
State Local Peer
LISTEN 127.0.0.1:45795 users:(("containerd",pid=3596596,fd=35))output
That one is on localhost, so nothing outside the machine can reach it. Its origin is easy to confirm:
go version /usr/bin/containerd
/usr/bin/containerd: go1.24.13output
A small Go server of my own listed the same way on *:8080, which is every interface.
To turn it off for one service, use a systemd drop-in:
[Service]
Environment=GODEBUG=multipathtcp=0/etc/systemd/system/containerd.service.d/mptcp.conf
sudo systemctl daemon-reload
sudo systemctl restart containerd
sudo ss -Mlnp
The list is then empty for a correct reason, and containerd shows up under ss -tlnp as plain TCP.
This doesn’t fix the bug. Per-program switches are fragile in the Go team’s view, as a single missed listener leaves the machine exposed. They and AlmaLinux both say the underlying bug isn’t specific to multipath TCP, and CIQ warns that net.mptcp.enabled=0 alone leaves the plain TCP path reachable.
How the bug works
A use-after-free means code keeps a pointer to memory that was already released. The allocator can hand that memory to something else, and a read through the old pointer then returns whatever lives there now. In the kernel that can be any kernel data, so reads through the stale pointer may leak secrets and writes may corrupt state.
Here the memory holds IPv4 options, which the kernel saves when a SYN carries them because its SYN-ACK has to repeat them. The steps come from the kernel commit message:
- A SYN arrives. Linux keeps a small request socket instead of a full socket, with the options attached as
ireq_opt. - The final ACK arrives.
tcp_v4_syn_recv_sock()creates the child socket and transfersireq_optto it asinet_optwithout copying. - Another CPU processes a retransmitted SYN for the same request socket and builds a SYN-ACK from
tcp_check_req(), reading those options underrcu_read_lock(). - The child socket is torn down.
inet_sock_destruct()freesinet_optwith a plainkfree(), right away. - The reader on the second CPU hasn’t finished.
ip_options_build()is where the use-after-free lands, andopt->optlengets read twice along the way.
Three outcomes are on the kernel team’s list: an out-of-bounds write, a crash, or nearby kernel memory going out in the SYN-ACK.
A second path exists through request socket migration (net.ipv4.tcp_migrate_req=1 or a BPF program). The clone and the old request socket share ireq_opt, and tcp_v4_reqsk_destructor() also used plain kfree().
IPv6 avoids the first issue because tcp_v6_syn_recv_sock() duplicates the options. It has the same migration issue with ipv6_opt, which only CALIPSO sets, and that gets a separate patch.
The window dates to commit 079096f103fa in October 2015, when processing request sockets stopped requiring the listener lock.
The fix
It changes two lines:
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ void inet_sock_destruct(struct sock *sk)
- kfree(rcu_dereference_protected(inet->inet_opt, 1));
+ kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
- kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1));
+ kfree_rcu(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1), rcu);
The readers were using RCU already, and other paths that replace inet_opt already used kfree_rcu(). With RCU, a reader marks where its read starts and ends. kfree_rcu() holds the memory until a grace period passes, meaning every reader inside at that moment has left. Only these two frees skipped that wait.
8.1 or 9.8
| Source | Score |
|---|---|
| Kernel CVE team, Ubuntu | 9.8 |
| Red Hat | 9.8, raised from 8.1 on October 30 |
| Oracle, SUSE, Amazon | 8.1 |
The gap is one CVSS field, attack complexity. A 9.8 sets it to low. An 8.1 sets it to high, reasoning that winning a race is hard, and Red Hat’s bulletin also mentions the precise timing involved.
Anthropic says an unreleased model built a remote root exploit against a server with a multipath TCP listener, and that a lost race only fails that one handshake, so the attacker can try again. Nobody outside Anthropic has reproduced this as far as I can tell: the exploit isn’t public, no vendor reported attacks in the wild, and it wasn’t on CISA’s known exploited list when I checked.
Timeline
| Date (2026) | Event |
|---|---|
| October 1 | Fix written by Eric Dumazet, with the report credited to Xinyang Ge of Anthropic |
| October 15 | In stable kernels. CVE published |
| October 24 | Kernel CVE team scores it 9.8 |
| October 27 | Anthropic describes its model’s result |
| October 30 | Red Hat bulletin moves to 9.8 |