Almost everything I run in production is a Go binary on a kernel I do not control. That split is why CVE-2026-98432 has held my attention all week: the bug is in the kernel, the fix is two lines, and the configuration Anthropic used to get remote root is what the Go runtime does by default now.
The kernel CVE team published it on October 15, 2026, for a use-after-free in the IPv4 TCP handshake, and added a CVSS 3.1 score of 9.8 on October 24. The fix went upstream in early October, before the CVE was public. Three weeks later, RHEL 8, 9 and 10 and every Ubuntu release still have no fixed kernel.
🐛 The bug is a handshake race, and the fix is two words
When a Linux server accepts a TCP connection, the kernel keeps the half-open handshake in a request socket, and any IPv4 header options from the client are stored in ireq_opt. When the handshake completes, tcp_v4_syn_recv_sock() hands that pointer to the child socket without copying it, so both reference the same memory.
Request sockets are processed without holding the listener lock, which is the point of the ehash design. So a retransmitted SYN can be picked up by another CPU that calls tcp_v4_send_synack() and ip_options_build() to build a reply from those same options, under rcu_read_lock() only. If the child socket is torn down in that window, inet_sock_destruct() frees inet_opt with a plain kfree(), and the CPU building the SYNACK reads freed memory. TCP child sockets don’t carry SOCK_RCU_FREE, so nothing delays the free.
Eric Dumazet’s fix, commit e3f33b0a1d89d738e2b913dab519226eaf76e15b, changes two lines: kfree() becomes kfree_rcu() in inet_sock_destruct() in net/ipv4/af_inet.c, and in tcp_v4_reqsk_destructor() in net/ipv4/tcp_ipv4.c.
The commit credits Xinyang Ge of Anthropic for the report and Kuniyuki Iwashima for review. It traces the bug to 079096f103fa (“tcp/dccp: install syn_recv requests into ehash table”), which shipped in Linux 4.4 in January 2016, plus a migration path from c905dee62232. The trigger is a normal-looking SYN carrying Record Route or Timestamp options. Nothing stops a hostile client from sending them. IPv6 escapes the main path because tcp_v6_syn_recv_sock() duplicates the options; a separate ipv6_opt case for CALIPSO needs another patch.
🚨 Your Go listener is the exact shape of the exploit
Here is the part that matters for backend teams. Multipath TCP (MPTCP) lets one connection span several network paths, and on Linux an application has to ask for it. Since Go 1.24, the net package asks for it on listen sockets by default, while outgoing connections stay plain TCP.
The Go security team sent an advisory to golang-announce on October 29, forwarded to oss-security by Alan Coopersmith. Neal Patel wrote it: the demonstrated exploit requires an MPTCP listener, the underlying bug is not MPTCP specific, and “it is possible that systems with no MPTCP listeners are vulnerable to similar attacks.” The best fix, he says, is a patched kernel.
The opt-out exists but nobody calls it a fix. GODEBUG=multipathtcp=0 disables it at runtime, and a godebug multipathtcp=0 line in go.mod or //go:debug multipathtcp=0 above package main changes the built default. The advisory calls this “a fragile mitigation” because one forgotten listener leaves the system exposed, and because it assumes every viable exploit depends on MPTCP, which nobody has shown.
Fangliding opened proposal golang/go#82717, “net: Disable MPTCP by default,” the same day. Go contributor neild replied that the root cause “is not MPTCP-specific,” that nobody knows whether a viable path to RCE exists without a listener, and that “I would recommend against hoping that there is not.” The team’s position is that changing Go’s default would be premature. The proposal is open, and Canonical’s Pebble already carries a mitigation commit referencing it.
KrakenD verified that its EE 3.0.2 build, with Go 1.26.10, listens on port 8080 with an MPTCP socket in its default configuration. Clients that don’t ask for MPTCP still get plain TCP, but the exploit only needs the listening socket. On enterprise Linux, EL 8, 9 and 10 ship MPTCP off in the kernel, so a stock RHEL host can’t open a listener even if the binary asks; you still run the vulnerable handshake, you just lose the demonstrated path to root.
⚖️ Anthropic’s scope is narrower than the CVE, and the scores disagree
The MPTCP precondition comes from one place: Anthropic’s October 27 research post from the Frontier Red Team. Neither the CVE record nor the fix commit mentions multipath TCP at all, and The Hacker News flagged that gap explicitly.
That matters because people read the CVE, see no mention of a feature they don’t use, and move on. The CNA’s scoring notes do describe the stale options leaking adjacent kernel heap memory to the peer and steering out-of-bounds writes, or crashing the machine. Anthropic’s chain is that description put to work: win the race so the kernel copies extra bytes back, harvest a kernel pointer to defeat KASLR, then reuse the overflow to overwrite a callback pointer with a payload already staged in kernel memory. Their test took 48 minutes to leak the pointer and five more to run a shell command as root. A lost race only fails the handshake, so an attacker can retry indefinitely.
Anthropic published no exploit code, no kernel version and no configuration, and as of October 30 nobody had publicly reproduced it. The fair reading is that the bug is confirmed and the worst case is plausible but not independently demonstrated.
The severity numbers are a mess. The kernel CNA says 9.8 with AC:L, arguing both sides of the race are attacker induced. Red Hat’s CVE page says Moderate, 5.9, with AC:H and C:N/I:N/A:H: crash, no confidentiality or integrity impact demonstrated. Red Hat’s own CSAF advisory file for the same CVE, updated October 29, says Important, 8.1, with high confidentiality and integrity impact. Oracle and SUSE score 8.1 on that vector, Amazon 7.0, and Ubuntu lands at 8.3 High using CVSS v4.0. Same bug, six numbers between 5.9 and 9.8.
🗓️ The patch gap is the actual story
Stable releases carrying the fix went out October 11 and 15: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, and 7.3. What happened next divides the ecosystem cleanly.
Debian fixed trixie (6.12.113-1, DSA-6568-1) on October 16, then bookworm (6.1.190-1 in DLA-4841-1 and linux-6.12 6.12.113-1~deb12u1 in DLA-4850-1). Oracle fixed UEK on October 16 with ELSA-2026-500397 through ELSA-2026-500399. Amazon fixed kernel6.18 on October 24 (ALAS2023-2026-3251) and kernel6.12 on October 29 (ALAS2023-2026-3335). SUSE shipped kernel-default 6.12.0-160000.40.1. AlmaLinux put patched kernels in testing on October 30 and said its technical steering committee, ALESCo, chose to backport ahead of RHEL.
Red Hat has not shipped one. Its CVE page says fixes “are currently deferred to a future update” for RHEL 8, 9 and 10, including the real-time kernel and the CoreOS nodes behind OpenShift Container Platform 4, and that no mitigation meets its criteria. No date is given.
Ubuntu is the same story with different bookkeeping. Every supported release reads Vulnerable or “work in progress”: 26.10 at 7.3.0-10.10, 24.04 at 6.8.0-149.149i1, 22.04 at 5.15.0-203.213i1, with 20.04, 18.04 and 16.04 plain Vulnerable, plus the cloud, Azure, AWS, KVM and real-time kernels. No Ubuntu Security Notice has been published, and the page I pulled today still says last updated October 22.
Nothing in the vendor advisories, the CVE record or Anthropic’s post reports exploitation in the wild, and the bug was not in the CISA KEV catalog as of the copies I checked. That’s the one reassuring fact, and it’s about the past.
🧰 What I would actually do this weekend
Start with the kernel. uname -r tells you what’s running, but the fix lives under a distribution version, so compare against the vendor tracker, not the upstream branch. If dpkg -l 'linux-image*' or rpm -q kernel shows a newer kernel installed than the one running, the fix isn’t active until you reboot. Do this on container hosts and Kubernetes nodes, because a container reports the host kernel.
Then find out whether anything listens with MPTCP. ss -H -lMn prints one line per MPTCP listening socket and nothing else, and sysctl net.mptcp.enabled says whether the kernel would allow one. An empty result means no listener right now, not immunity.
If you have Go services and no patched kernel, multipathtcp=0 removes the demonstrated path and leaves the bug. Treat it as reducing blast radius while you chase the kernel, and put it in go.mod rather than an environment variable so it survives redeploys. Dropping inbound IPv4 TCP packets that carry options is the other lever, and it’s unconfirmed, so try it in staging first. Filtering IP options can break path MTU discovery.
On managed Kubernetes, check the node image. Amazon shipped fixed Amazon Linux 2023 kernels. AKS and GKE nodes on Ubuntu do not have one yet, and that’s a provider conversation, not a Kubernetes upgrade.
🧠 Final Thoughts
The headline is that a model found a remote root bug in the kernel. What I’ll remember is that the eligibility condition for that exploit, an MPTCP listener, was made the default for a large slice of backend services by a language runtime, and the fix for the underlying bug is two kfree to kfree_rcu edits that most of the enterprise Linux fleet still can’t install three weeks later.
Both halves looked fine in isolation: ship the fix as small as possible, enable the useful transport feature by default. They compose badly. And “we don’t use MPTCP” is not a security claim, it’s a hypothesis the Go security team explicitly declined to endorse. ss -H -lMn takes four seconds to test.
Thanks for reading.