critical

CVE

CVE-2026-98432

CWE

CWE-416, CWE-362, CWE-787

Affected Surface

  • Linux kernel versions `4.4` (commit `079096f103fa`) through `< 5.10.272`, `< 5.15.223`, `< 6.1.190`, `< 6.6.159`, `< 6.12.113`, `< 6.18.56`, `< 7.2.10`, and `< 7.3-rc7` (`CVE-2026-98432`, CVSS 9.8 Critical)
  • Go `>= 1.24` (`1.24.x`, `1.25.x`, `1.26.x`) network services running on unpatched Linux kernels, because Go 1.24+ sets `GODEBUG=multipathtcp=2` by default on `net.Listen` sockets (`golang/go#82717`)

TL;DR

On 29 and 30 October 2026, the Go Security Team issued a security advisory (oss-security 2026/10/30/1 and golang/go#82717) warning that every Go 1.24+ server on Linux enables Multipath TCP (MPTCP) by default on listening sockets, matching the exact precondition required by a newly disclosed zero-click Linux kernel remote root exploit for CVE-2026-98432 (CVSS 9.8 Critical):

  1. The kernel bug (CVE-2026-98432): Introduced in Linux 4.4 (079096f103fa), tcp_v4_syn_recv_sock() transfers ownership of the IPv4 header options pointer ireq->ireq_opt from the half-open request socket to the newly created child socket (newinet->inet_opt) without copying it. While one CPU closes and destroys the child socket via inet_sock_destruct() (or migrates and destroys a cloned request socket via tcp_v4_reqsk_destructor()), another CPU processing a retransmitted SYN reads ireq->ireq_opt under rcu_read_lock() in tcp_v4_send_synack() -> ip_build_and_send_pkt() -> ip_options_build(). Because both destructors freed inet_opt / ireq_opt immediately with kfree() instead of waiting for an RCU grace period via kfree_rcu(), ip_options_build() reads opt->optlen twice from freed kernel heap memory.
  2. Zero-click remote root exploitation on MPTCP listeners: On 27 October 2026, Anthropic’s Frontier Red Team disclosed that its researcher (Xinyang Ge) used an internal model to turn CVE-2026-98432 into a two-stage unauthenticated remote root exploit against any Linux host with an exposed MPTCP listener. Because losing the SYN/close race only fails the TCP handshake without panicking the kernel on carefully chosen lengths, an attacker can retry continuously, leaking a kernel heap pointer in ~48 minutes to defeat KASLR and then overflowing the packet buffer in ~5 minutes to overwrite a callback pointer and execute a shell command as root.
  3. Why Go 1.24+ services are uniquely exposed: In Go 1.24 (commit 3d4daa38a7), the Go standard library changed the default GODEBUG setting to multipathtcp="2" (enable MPTCP on listeners only by default). Any HTTP server, API gateway (such as KrakenD, Caddy, Traefik, or a custom microservice), or gRPC server compiled with Go 1.24, 1.25, or 1.26 opens mptcp listening sockets on Linux even if no client ever negotiates MPTCP.

What to do now:

  1. Upgrade and reboot into a patched Linux kernel (>= 5.10.272, >= 5.15.223, >= 6.1.190, >= 6.6.159, >= 6.12.113, >= 6.18.56, >= 7.2.10, or >= 7.3).
  2. Immediately apply stopgap mitigations on unpatched hosts: Disable MPTCP system-wide with sudo sysctl -w net.mptcp.enabled=0 and start Go 1.24+ services with GODEBUG=multipathtcp=0 (or add godebug multipathtcp=0 to go.mod). Note that disabling MPTCP only removes the precondition used by the demonstrated exploit; the underlying inet_opt race lives in generic IPv4 TCP handling, so kernel patching remains mandatory.

Affected systems and fixed versions

ComponentIdentifierSeverityAffected versionsFixed version / MitigationVulnerable path
Linux kernel (net/ipv4)CVE-2026-98432CVSS 9.8 Critical (Kernel CNA) / 8.1 High (Red Hat)4.4 through < 5.10.272, < 5.15.223, < 6.1.190, < 6.6.159, < 6.12.113, < 6.18.56, < 7.2.10, < 7.3-rc75.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3inet_sock_destruct() in net/ipv4/af_inet.c and tcp_v4_reqsk_destructor() in net/ipv4/tcp_ipv4.c
Debian linux / linux-6.12CVE-2026-98432 (DSA-6568-1, DLA-4841-1, DLA-4850-1)CriticalDebian 12 (< 6.1.190-1, < 6.12.113-1~deb12u1) and Debian 13 (< 6.12.113-1)6.1.190-1, 6.12.113-1~deb12u1, 6.12.113-1Backported commit 11a03ce3c4a6
Go standard library (net)golang/go#82717 (oss-security 2026/10/30/1)High exposure preconditionGo >= 1.24.0 on unpatched Linux kernels with net.mptcp.enabled=1Set GODEBUG=multipathtcp=0 at runtime or godebug multipathtcp=0 in go.modsrc/internal/godebugs/table.go (multipathtcp="2" default on net.Listen)

Technical analysis

1. How inet_sock_destruct() frees inet_opt while tcp_v4_send_synack() is still reading it

When a Linux TCP listener receives an IPv4 SYN packet carrying IP header options (such as IPOPT_RR Record Route or IPOPT_TIMESTAMP), the kernel parses and stores those options in a struct ip_options_rcu pointed to by the half-open request socket (ireq->ireq_opt).

When the three-way handshake completes on the client’s ACK, tcp_v4_syn_recv_sock() allocates the full child socket (newinet) and transfers the ireq_opt pointer directly to newinet->inet_opt without copying the struct (xchg(&ireq->ireq_opt, NULL) or shared pointer during SYNACK retransmit).

Since Linux 4.4 (commit 079096f103fa, "tcp/dccp: install syn_recv requests into ehash table"), SYN_RECV request sockets are processed locklessly in the established hash table without holding the listener lock. That allows two CPUs to race on the same struct ip_options_rcu:

  1. CPU A (retransmitted SYN): Processes a concurrent retransmitted SYN for the same request socket inside tcp_check_req() -> tcp_v4_send_synack(). Both tcp_v4_send_synack() and inet_csk_route_req() dereference ireq->ireq_opt protected only by rcu_read_lock(), and pass that opt pointer to ip_build_and_send_pkt(), which reads opt->optlen to reserve skb header space and then calls ip_options_build(), which reads opt->optlen a second time to memcpy() the options into the outgoing SYN-ACK.
  2. CPU B (child socket teardown or request-socket migration): Immediately closes and destroys the child socket (which does not set SOCK_RCU_FREE), calling inet_sock_destruct(), or destroys a migrated request-socket clone in tcp_v4_reqsk_destructor().

Before Eric Dumazet’s fix (commit e3f33b0a1d89), both destructors freed the ip_options_rcu struct immediately with a plain kfree() while CPU A was still inside its rcu_read_lock() critical section:

--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -161,7 +161,7 @@ void inet_sock_destruct(struct sock *sk)
 	WARN_ON_ONCE(sk->sk_wmem_queued);
 	WARN_ON_ONCE(sk->sk_forward_alloc);
 
-	kfree(rcu_dereference_protected(inet->inet_opt, 1));
+	kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu);
 	dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
 	dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1));
 	psp_sk_assoc_free(sk);
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1209,7 +1209,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst,
  */
 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);
 }

2. Why the opt->optlen double-read yields both a KASLR leak and a heap overflow

When kfree() returns the ip_options_rcu object to its kmalloc slab while ip_build_and_send_pkt() is executing on another CPU, an attacker spraying another kernel object into that same slab slot between the two reads of opt->optlen gains two primitives:

  • Stage 1 (Remote KASLR bypass via overread): If the reallocated object places a larger byte value at the opt->optlen offset after ip_build_and_send_pkt() checks it, ip_options_build() copies up to that larger optlen from the freed/reallocated slab chunk directly into the outgoing SYN-ACK IP header sent back to the attacker over the network. As soon as one leaked SYN-ACK header contains a kernel pointer from adjacent slab data, the attacker computes the kernel’s KASLR slide.
  • Stage 2 (Control-flow hijack via out-of-bounds write): Using the same optlen / offset mismatch in ip_options_build(), the exploit overflows the buffer to overwrite a function callback pointer with the address of a ROP/function-call chain already staged in kernel memory via standard protocol primitives, executing an attacker-supplied shell command as root.

In Anthropic’s proof-of-concept against a Linux server with an MPTCP listener, losing the race simply aborts the handshake without crashing the target, allowing continuous retries: Stage 1 leaked a kernel pointer in roughly 48 minutes, and Stage 2 achieved remote root command execution in another 5 minutes.

3. Why Go 1.24+ servers on Linux expose MPTCP listeners automatically

On Linux kernels where net.mptcp.enabled is 1 (the default on modern Debian, Ubuntu, Fedora, and RHEL derivatives), an application creates an MPTCP listening socket by passing IPPROTO_MPTCP (262) instead of IPPROTO_TCP (6) to socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP).

In Go 1.24 (commit 3d4daa38a7), src/internal/godebugs/table.go changed the default multipathtcp setting from "0" to "2" (listeners only):

// Go 1.24+ GODEBUG values for multipathtcp (doc/godebug.md):
// "0": disable MPTCP on dialers and listeners by default
// "1": enable MPTCP on dialers and listeners by default
// "2": enable MPTCP on listeners only by default (Go 1.24+ default)
// "3": enable MPTCP on dialers only by default

As a result, any Linux service compiled with Go 1.24, 1.25, or 1.26 that calls net.Listen("tcp", ...) or http.ListenAndServe(...) creates an IPPROTO_MPTCP listening socket by default. Ordinary TCP clients still connect over standard TCP, so operators rarely notice that their Go binaries are listening on MPTCP until they inspect ss -Mltn.

Detection and remediation

1. Audit Linux hosts for unpatched kernels and active MPTCP listeners

# 1. Check the running Linux kernel version and whether MPTCP socket creation is enabled
uname -r
sysctl net.mptcp.enabled 2>/dev/null || true

# 2. List all active Multipath TCP (MPTCP) listening sockets and owning PIDs (such as Go 1.24+ services)
ss -Mltnp 2>/dev/null || true

# 3. Check Go binaries on the host or in container images to see if they were built with Go >= 1.24
for bin in /usr/local/bin/* /opt/*/bin/*; do
  [ -f "$bin" ] && go version -m "$bin" 2>/dev/null | head -n 2
done

2. Patch the kernel and apply immediate MPTCP / IP-options mitigations

  1. Upgrade the Linux kernel and reboot:
    • Upstream stable fixes: >= 5.10.272, >= 5.15.223, >= 6.1.190, >= 6.6.159, >= 6.12.113, >= 6.18.56, >= 7.2.10, or >= 7.3.
    • On Debian 12 (bookworm) and Debian 13 (trixie), upgrade to linux 6.1.190-1 (DLA-4841-1) or 6.12.113-1 (DSA-6568-1 / DLA-4850-1) and reboot the host (uname -r).
  2. Disable MPTCP socket creation at the kernel level (if MPTCP is not required):
    sudo sysctl -w net.mptcp.enabled=0
    echo "net.mptcp.enabled = 0" | sudo tee /etc/sysctl.d/99-disable-mptcp.conf
    Note that changing net.mptcp.enabled to 0 stops new MPTCP sockets from being created; restart any running Go services afterward and verify with ss -Mltnp that no mptcp listeners remain.
  3. Disable default MPTCP listeners in Go 1.24+ services:
    • At runtime (environment variable): Set GODEBUG=multipathtcp=0 in your systemd unit, Dockerfile, or Kubernetes Deployment manifest (if GODEBUG is already set, append ,multipathtcp=0).
    • At build time (go.mod): Add godebug multipathtcp=0 to the main module’s go.mod file:
      module example.com/myservice
      
      go 1.25.0
      godebug multipathtcp=0
    • Also check your codebase for explicit ListenConfig.SetMultipathTCP(true) calls (rg -n 'SetMultipathTCP' .), which override GODEBUG.
  4. Drop inbound IPv4 packets carrying IP options at the perimeter firewall: Because CVE-2026-98432 requires a SYN packet with non-empty IPv4 header options (ireq_opt / inet_opt, where IPv4 ihl > 5), dropping inbound TCP packets with IPv4 options in nftables (ip hdrlength > 20 tcp flags syn drop) or cloud security appliances blocks the vulnerable ireq_opt allocation path across all TCP and MPTCP listeners while kernel reboots are scheduled.

Timeline

  • 2015-10-02: Linux 4.4 merges commit 079096f103fa ("tcp/dccp: install syn_recv requests into ehash table"), introducing lockless SYN_RECV request-socket handling.
  • 2026-10-01: Eric Dumazet submits the patch "ipv4: free inet_opt and ireq_opt after an RCU grace period" (e3f33b0a1d89), reported by Xinyang Ge of Anthropic.
  • 2026-10-15: linux-cve-announce publishes CVE-2026-98432 as stable kernel backports (6.12.113, 6.18.56, 7.2.10) ship.
  • 2026-10-27: Anthropic’s Frontier Red Team publishes its research write-up demonstrating zero-click unauthenticated remote root code execution via CVE-2026-98432 against Linux servers with an MPTCP listener.
  • 2026-10-29 (20:17 to 23:34 UTC) and 2026-10-30: Issue golang/go#82717 is opened and the Go Security Team publishes [security] Protecting against CVE-2026-98432 on golang-announce and oss-security (2026/10/30/1), detailing GODEBUG=multipathtcp=0 and godebug multipathtcp=0 mitigations for Go 1.24+ servers.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Use AI-native static analysis to find similar application vulnerabilities and generate review-ready fixes.

References