DEV Community

Cover image for A 9.8 Linux TCP Bug Gave Remote Root in 53 Minutes. Patch Your Servers
Lycore Development
Lycore Development

Posted on Edited on

A 9.8 Linux TCP Bug Gave Remote Root in 53 Minutes. Patch Your Servers

Most security bugs we write about need something from you first: a malicious extension you installed, a key you pasted into a dashboard, a library you forgot to update. This one needs nothing. CVE-2026-98432 is a race condition in the Linux kernel's IPv4 TCP code, and the only requirement for reaching the vulnerable path is that your server accepts TCP connections.

The bug was fixed upstream weeks ago. It became urgent this week, because three things landed on top of each other: Anthropic published a working remote root exploit, the Go team warned that Go services quietly opt into the exact feature that exploit uses, and Red Hat issued a Critical bulletin while several distributions still had no patched kernel to install.

This post sticks to what the kernel CVE team, Anthropic, the Go security team, Red Hat, Ubuntu, CIQ and Akamai/Linode have published. Then it turns that into a short, practical triage you can run today.

What happened, in order

  • Early October: the fix (commit e3f33b0a) landed in Linux 7.3-rc7 and was backported to the stable branches: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56 and 7.2.10.
  • October 15: The Linux kernel CVE team published CVE-2026-98432 and scored it 9.8 (CVSS 3.1, network, no privileges, no user interaction). The bug goes back to kernel 4.4.
  • October 27: Anthropic's Frontier Red Team published a post on vulnerabilities found and exploited with Claude. One section describes a zero-click exploit for this CVE, written by an unreleased internal research model "after initial prompting".
  • October 29: The Go security team posted "Protecting against CVE-2026-98432" to golang-announce, pointing out that Go programs enable Multipath TCP (MPTCP) by default on Linux since Go 1.24.
  • October 30: Red Hat published bulletin RHSB-2026-016 with a Critical impact rating for RHEL 8, 9 and 10 and OpenShift, plus an interim firewall rule. CIQ published a mitigation guide for Rocky Linux, noting that no patched CIQ kernel had shipped yet. Akamai posted a customer advisory for Linode.
  • October 31 (01:55 UTC): Akamai's update says it is deploying mitigations for the known attack vector, has "no evidence of this vulnerability being exploited" on its compute platform, and strongly advises customers to apply OS updates from their upstream provider.

When I checked on October 31, CISA's Known Exploited Vulnerabilities catalog (version 2026.10.30) had no entry for this CVE. That means no confirmed in-the-wild exploitation has been listed, not that none is happening.

The bug, in plain terms

When a server receives a TCP SYN that carries IPv4 options (things like Record Route or Timestamp in the IP header), the kernel stores those options on the pending connection request. When the handshake completes, ownership of that options buffer moves to the new child socket without copying it.

The kernel advisory explains the race: another CPU can be processing a retransmitted SYN for the same request at the same moment and building a SYN-ACK from those same options. If the child socket gets freed first, the options memory is released with a plain kfree() while the other CPU is still reading it. That's a use-after-free. A similar problem exists when request sockets are migrated (net.ipv4.tcp_migrate_req=1 or a BPF_SK_REUSEPORT_SELECT_OR_MIGRATE program).

The fix is small: free those buffers with kfree_rcu() so they survive until concurrent readers are done. Small fixes for old race conditions are exactly the ones that sit unpatched in fleets, because nobody notices them until someone shows an exploit.

IPv6 is not affected by the first issue, according to the commit message, because the IPv6 path copies the options.

What Anthropic actually demonstrated

The Anthropic post is specific about the scope, and it's worth reading carefully rather than via headlines:

  • The exploit targets Linux servers with a multipath TCP listener. An attacker sends packets and ends up running an arbitrary command as root, with no credentials and no user interaction.
  • Stage one defeats KASLR remotely: the race makes the kernel copy extra bytes and send them back, and eventually one reply contains a kernel pointer.
  • Stage two uses the same bug to overwrite a callback pointer and run a chain of existing kernel functions that ends in a shell command.
  • The detail that matters most for defenders: a lost race only fails the handshake. It doesn't crash the box. An attacker can just keep retrying.
  • In their proof of concept, leaking a kernel pointer took 48 minutes, and reaching command execution took about five more.

Anthropic hasn't published the exploit code. The fact that a model built this chain is the reason the story spread so fast, but for your servers the practical point is simpler: a remote root exploit for this bug exists, and the technique is now publicly described.

The MPTCP detail, and why Go teams should read twice

MPTCP is an extension that lets one connection use several network paths. On Linux, applications opt in per socket, and the net.mptcp.enabled sysctl controls whether the kernel allows it at all. CIQ found it off by default on the RHEL-family kernels it tested; other distributions may differ, so check.

Here's the catch the Go team flagged: since Go 1.24, Go programs enable MPTCP by default for listening sockets on Linux. If your API gateway, a sidecar, a metrics exporter or an internal tool is written in Go and built with 1.24 or newer, it may be exposing exactly the kind of listener Anthropic's exploit targets, without anyone on your team having chosen that.

The Go team's guidance:

# Runtime: disable the MPTCP default for one program
GODEBUG=multipathtcp=0 ./your-service
Enter fullscreen mode Exit fullscreen mode
// Build time: add to the main module's go.mod
godebug multipathtcp=0
Enter fullscreen mode Exit fullscreen mode

But they are just as clear that this is a fragile mitigation. One forgotten MPTCP listener leaves the host exposed, and it assumes every viable exploit needs MPTCP. Their words: "the underlying bug is not specific to MPTCP." CIQ backed that up in testing: with net.mptcp.enabled=0, a plain TCP listener on every kernel they tested still answered a SYN carrying a Record Route option, which means the vulnerable code path was still reachable.

So: turning off MPTCP reduces exposure to the demonstrated exploit. It doesn't fix the bug.

Who is exposed

Red Hat's bulletin puts it plainly: the bug affects any system running a vulnerable kernel with IPv4 TCP enabled, and "systems accepting inbound TCP connections are most directly exposed." In practice:

  • VMs and bare-metal servers running RHEL 8/9/10 and rebuilds (Rocky, Alma), Ubuntu, Debian and others on affected kernels. Upstream lists RHEL 6 and 7 kernels as not affected.
  • Kubernetes nodes. Containers share the host kernel. Rebuilding your container images does nothing here. The node OS is what needs the patch.
  • Managed platforms. Akamai told Linode customers to apply OS updates to their workloads themselves. If you run your own VMs on any cloud, assume the kernel is your job unless your provider says otherwise.

When I checked Ubuntu's CVE tracker (last updated October 30), the main kernel packages for supported releases were still marked "Vulnerable" with fixes "work in progress", and CIQ had no patched kernels for the variants it checked. So for a lot of teams, "just patch" isn't available yet. That's why the next section has an interim step.

A triage you can run today

1. Inventory kernels. On every host that accepts inbound connections:

uname -r
Enter fullscreen mode Exit fullscreen mode

Compare against your vendor's advisory, not just the upstream version list. Distro kernels backport fixes under their own version numbers.

2. Check whether MPTCP is on, and who is listening with it.

sysctl net.mptcp.enabled
ss -Mltn
Enter fullscreen mode Exit fullscreen mode

CIQ notes that on newer kernels ss -Mltn shows mptcp rows for MPTCP listeners, while on some older ones it doesn't, so trust the sysctl there.

3. Find your Go binaries. For each service binary:

go version -m /path/to/binary | head -1
Enter fullscreen mode Exit fullscreen mode

Anything built with Go 1.24 or newer listens with MPTCP by default (unless you've overridden it). Add GODEBUG=multipathtcp=0 to its environment as a stopgap, but don't stop there.

4. Apply the interim filter where no patched kernel exists. Red Hat's bulletin gives an nftables table that drops incoming IPv4 TCP packets that carry IP options (a header longer than 20 bytes):

table inet cve_2026_98432 {
    chain input {
        type filter hook input priority -310; policy accept;
        ip protocol tcp ip hdrlength > 5 counter drop
    }
}
Enter fullscreen mode Exit fullscreen mode
sudo nft --check --file cve-2026-98432.nft
sudo nft --file cve-2026-98432.nft
sudo nft list table inet cve_2026_98432
Enter fullscreen mode Exit fullscreen mode

Red Hat says normal application traffic should be fine, because ordinary TCP options live in the TCP header, not the IP header. They also say clearly that this reduces exposure but cannot fully prevent exploitation, and that you should test it before production. CIQ adds a gotcha worth knowing: stopping the stock nftables.service flushes the whole ruleset, including this table.

5. Patch and reboot as soon as your vendor ships. A kernel fix isn't live until the host runs the new kernel. Then remove the interim rule (sudo nft delete table inet cve_2026_98432) and record the running version.

6. Put the boring stuff first. Hosts that face the internet directly (load balancers, bastions, anything with a public IP) go first. Internal hosts behind a load balancer that terminates TCP are less exposed, but not immune to anything that can reach them from inside.

What we do on our projects

Most of what we build for clients is Django (plus some .NET) running on Linux servers, with Flutter and React front ends. For a kernel bug like this, our routine is the same every time: inventory first (which hosts accept inbound TCP, which kernel each runs), internet-facing hosts first, interim mitigation only where the vendor has no fix yet, and a scheduled reboot window instead of an ad-hoc one. The step this bug adds to our checklist is asking which processes on each host are Go binaries (proxies, exporters and CLI-installed agents count) and how they were built, because a language default is not something we used to think about during kernel triage. The slowest part is never the patch. It's finding every host that needs it.

What's still unclear

  • Whether hosts without an MPTCP listener can be exploited the same way. Anthropic only demonstrated the MPTCP case. The Go team says "it is possible that systems with no MPTCP listeners are vulnerable to similar attacks." Treat every vulnerable kernel as exposed.
  • Severity scores differ by source. The kernel CNA gives 9.8 (CVSS 3.1). Ubuntu's page also shows a CVSS 4.0 score of 8.3. Red Hat rates the impact Critical. The ranking doesn't change what you should do.
  • Patch timelines. These vary by distribution and are moving daily. Check your vendor's tracker rather than any blog post, including this one.

I'll update this post if exploitation in the wild is confirmed or major distributions ship fixes.

How many of your servers would you have to log into to answer "are we patched?"

Honestly, for most teams the answer is "all of them". Do you have a single place that shows the running kernel version of every host you own? And did anyone on your team know Go turned on MPTCP by default? Tell me in the comments.

Top comments (0)