If you run Go services built with Go 1.24 or later on Linux, each net.Listen("tcp", ...) also opens an MPTCP listening socket, and plain ss -tln does not show it. Run ss -tlnM instead: any line starting with mptcp is a listener that meets the precondition of the public CVE-2026-98432 root exploit. Setting GODEBUG=multipathtcp=0 (or godebug multipathtcp=0 in go.mod) removes that socket. The real fix is a kernel at or past 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56 or 7.2.10.
We tested all of this with Go 1.24.7 on Linux 6.18.44 in a Linux container on 2 Nov 2026, with iproute2 6.1.0 for ss.
Why we did this: the backend for our apps runs a few Go services next to Laravel and Node on our Ubuntu KVM, and Ubuntu had not confirmed a fixed kernel when the Go Security Team’s notice went out on 29 Oct. Before changing any systemd unit we wanted to see exactly what Go opens, and how to prove a change worked.
What CVE-2026-98432 is, briefly
CVE-2026-98432 is a use-after-free in the Linux IPv4 TCP code, published on 15 Oct 2026. The kernel CNA scores it 9.8; Red Hat scores it 8.1 because it rates the attack complexity as high. It affects kernels from 4.4 up to the fixed releases listed above.
The demonstrated exploit, which gives unauthenticated root, needs an MPTCP listener on the target. The bug itself is not MPTCP-specific, and nobody has said whether root is reachable without one. So removing MPTCP listeners takes away the demonstrated precondition, not the bug.
Distro status as reported on 30 Oct: Debian 12 and 13 had fixed kernels; RHEL 8, 9 and 10 were listed as affected with no fixed packages; Ubuntu had no confirmed fix on its tracker. Check the Ubuntu CVE page for your release on the day you read this.
Why Go matters here
Since Go 1.24, Go enables MPTCP by default for listen sockets on Linux. The Go team’s notice of 29 Oct says it plainly and calls per-program opt-outs a “fragile mitigation”: one forgotten listener is enough. It also says the team considers it premature to change Go’s default because of this bug.
To see it, we built a 25-line server that listens on 127.0.0.1:8081 with net.Listen and nothing else, with go 1.24 in go.mod:
ln, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
panic(err)
}

Real output from the container. The default build gets an extra mptcp socket; the environment variable removes it.
Two things stood out:
ss -tln 'sport = :8081'printed exactly one line in both runs. Without-M(--mptcp) you cannot tell the difference, so a quick port audit with the usual flags misses this completely.- The same listener shows up twice with
-M: once astcpand once asmptcp. Clients that only speak TCP still connect normally, which is why nothing looks broken.
Three ways to turn it off, tested
All three removed the mptcp line from ss -tlnM for our test server.
1. Environment variable, no rebuild. Good for a running fleet:
GODEBUG=multipathtcp=0 ./server
In a systemd unit that is one line under [Service], followed by systemctl daemon-reload and a restart of the service. If the unit already sets GODEBUG, add the setting to the existing value with a comma; a second Environment=GODEBUG= line replaces the first.
[Service]
Environment=GODEBUG=multipathtcp=0
2. go.mod, at build time. Survives a unit file being rewritten by a deploy tool:
module example.com/server
go 1.24
godebug multipathtcp=0
3. The go line itself. A module that still says go 1.23 gets the old default even when built with a 1.24 toolchain, because Go picks GODEBUG defaults from the module’s language version. Our go 1.23 build of the same code had no MPTCP listener.
There is also a per-socket switch, net.ListenConfig.SetMultipathTCP(false), which overrides GODEBUG. That cuts both ways: if a library calls SetMultipathTCP(true), your environment variable will not stop it, so check ss -tlnM after the change rather than trusting the config.
Audit the binaries without running them
Go embeds the effective defaults in each binary. go version -m prints them, so you can check what is deployed without starting anything:
go version -m ./server | grep DefaultGODEBUG
Our godebug build printed DefaultGODEBUG=multipathtcp=0. The go 1.23 build printed a longer list that also contained multipathtcp=0. The plain go 1.24 build printed no DefaultGODEBUG line at all, which means it uses the 1.24 defaults, MPTCP on.
A read-only check script
We put the three checks in one script: kernel version against the upstream fix for its series, the net.mptcp.enabled sysctl, and every MPTCP listener with its process, Go version and GODEBUG settings. It changes nothing.
#!/usr/bin/env bash
# mptcp-check.sh: CVE-2026-98432 exposure check. Read-only. Run as root so ss can name processes.
set -u
fixed="5.10.272 5.15.223 6.1.190 6.6.159 6.12.113 6.18.56 7.2.10"
k=$(uname -r | cut -d- -f1); series=${k%.*}
echo "kernel: $(uname -r)"
for f in $fixed; do
if [ "${f%.*}" = "$series" ]; then
if [ "$(printf '%s\n%s\n' "$f" "$k" | sort -V | head -1)" = "$f" ]; then
echo " upstream $series fix is $f: this version is at or past it"
else
echo " upstream $series fix is $f: this version is OLDER (check your distro's backport notice)"
fi
fi
done
echo "net.mptcp.enabled = $(sysctl -n net.mptcp.enabled 2>/dev/null || echo 'n/a (no MPTCP in kernel)')"
echo "MPTCP listeners:"
ss -Hltnp -M 2>/dev/null | awk '$1=="mptcp"' | sed 's/^/ /'
for pid in $(ss -Hltnp -M 2>/dev/null | awk '$1=="mptcp"' | grep -o 'pid=[0-9]*' | cut -d= -f2 | sort -u); do
exe=$(readlink -f /proc/$pid/exe)
gv=$(go version -m "$exe" 2>/dev/null | head -1)
dg=$(go version -m "$exe" 2>/dev/null | grep -o 'DefaultGODEBUG=[^ ]*')
echo " pid $pid $exe ${gv:+[$gv]} ${dg:-}"
tr '\0' '\n' < /proc/$pid/environ 2>/dev/null | grep '^GODEBUG=' | sed 's/^/ env /'
done

The script run in the same container. The second listener belongs to the container’s own management process, not to our test.
The run made a useful point by accident: the container had an MPTCP listener we had not started. On a real server, expect the same from Go-based tools you installed rather than wrote (agents, exporters, proxies). A distro kernel version number like Ubuntu’s 6.8.0-xx will not match the upstream list either, so treat an “OLDER” result as “go and read your distro’s notice”, not as proof of exposure.
The blunt option: the sysctl
net.mptcp.enabled defaults to 1. Setting it to 0 stops new MPTCP sockets from being created for every process at once, which is less fragile than chasing each service. We did not toggle it in this container, so we have no output to show for it; the semantics here come from the kernel documentation and the advisory write-ups. If nothing you run depends on MPTCP (most web backends don’t), it is the simplest stopgap until a fixed kernel lands, and it still leaves the underlying TCP bug in place.
What to do today
- Run
ss -tlnM(or the script above) on every Linux box with Go services. - For each
mptcplistener, addGODEBUG=multipathtcp=0or thegodebugline, restart, and runss -tlnMagain. - Consider
net.mptcp.enabled=0if you cannot account for every listener. - Install the fixed kernel as soon as your distro ships it and reboot; that is the actual fix.
Sources: the Go Security Team notice on oss-security (29 Oct 2026), lilting.ch’s CVE-2026-98432 summary with the fixed-version list (updated 30 Oct 2026), and Go issue 82717 for the discussion on Go’s default.



