CVE-2026-98432 isn’t an MPTCP bug, even though most write-ups lead with multipath TCP. It is a use-after-free in the IPv4 TCP handshake code of the kernel. A retransmitted SYN races the creation of the child socket, and ip_options_build() reads IP options the kernel has already freed. MPTCP enters the story because the one demonstrated exploit, the zero-click root shell Anthropic described, needs an MPTCP listener to land.
So the real fix is a kernel package, and on 31 October 2026 Debian is the only one of the distros tested here that ships it. This guide shows you how to check your running kernel against each distro tracker and how to find the MPTCP listeners you didn’t know you had, because Go opens them by default. It also covers what switching MPTCP off does and does not buy you, and what the Debian upgrade looks like before and after. Everything below was run on Ubuntu 24.04, Rocky Linux 9 and 10, and Debian 13 in October 2026.
The bug lives in IPv4 TCP code
Is your server affected? If it runs an unpatched kernel and accepts IPv4 TCP connections, the vulnerable code runs on it. Red Hat goes furthest in its RHSB-2026-016 bulletin: the flaw affects any system with IPv4 TCP networking enabled, and systems that accept inbound TCP connections are the most directly exposed. What no vendor has published is a working exploit against a plain TCP listener on a default configuration. The Debian security tracker and the Ubuntu page describe the race without naming which listener types are reachable.
The primary sources say four things, in the order they were published:
- The fix commit (
e3f33b0a1d89):tcp_v4_syn_recv_sock()hands the IP options of the request to the child socket without copying them, and the child frees them with a plainkfree(). IPv6 is not affected by that first issue. - The same commit: a second path exists through request socket migration, when
net.ipv4.tcp_migrate_req=1or a BPF reuseport program migrates requests. - The Anthropic write-up: the working exploit targets servers with an MPTCP listener, takes 48 minutes to leak a kernel pointer and five more to run a shell command as root.
- The Go security team advisory of 29 October: “the underlying bug is not specific to MPTCP. It is possible that systems with no MPTCP listeners are vulnerable to similar attacks.”
Read that as two separate facts. An MPTCP listener puts you inside the proven exploit. No MPTCP listener takes you out of the proven exploit, but not out of the bug, so you patch either way. Severity doesn’t give you an out either, because Ubuntu rates it High with the 9.8 CVSS score from the CNA, the Red Hat page shows the same 9.8 marked as preliminary, and the Red Hat bulletin rates it Critical. A network-reachable kernel bug with no authentication step is one you schedule a reboot for this week, not next quarter.
Debian ships the fixed kernel first
Of the distros in this guide, Debian is the only one with a fixed kernel in its archive as of 31 October 2026. Ubuntu marks its standard-support releases “Vulnerable, work in progress” (the ESM releases show plain “Vulnerable”), and Red Hat lists no erratum, so Rocky has nothing to rebuild yet. Rolling distros with a 7.2.10 or newer kernel already carry the upstream fix. These pages change daily, so treat the table as a dated snapshot and open the tracker before you act on it.
| Distro | Status on 31 Oct 2026 | Fixed package | Live tracker |
|---|---|---|---|
| Debian 13 trixie | Fixed, DSA-6568-1 | linux 6.12.113-1 | Debian |
| Debian 12 bookworm | Fixed, DLA-4841-1 and DLA-4850-1 | linux 6.1.190-1, or linux-6.12 6.12.113-1~deb12u1 | Debian |
| Ubuntu 26.10, 26.04, 24.04, 22.04 | Vulnerable, work in progress | None yet | Ubuntu |
| RHEL 8, 9 and 10 | No erratum; RHSB-2026-016 gives an nftables filter as mitigation | None yet | Red Hat |
| Rocky Linux 9 and 10 | No advisory in dnf updateinfo; newest kernel changelogs don’t mention it | None yet | Rocky errata |
If you build your own kernels, you need upstream commit e3f33b0a1d89. We checked the kernel.org ChangeLog for each stable branch and found the backport first in these releases:
- 7.3 (mainline) and 7.2.10
- 6.18.56 and 6.12.113
- 6.6.159 and 6.1.190
- 5.15.223 and 5.10.272
Those floors only apply to vanilla kernels. Distro kernels backport fixes into their own version numbers, so the Ubuntu 6.8 and Rocky 5.14 or 6.12 builds will never match the upstream list. A Rocky kernel called 6.12.0 carries patches from much later 6.12.y releases, and an Ubuntu 6.8 kernel can carry the fix without its version moving past 6.8. On those, the package changelog is the only proof that counts, and you should ignore any scanner that just compares version strings.
The package changelog proves the fix
You need two answers: which kernel is running, and whether that kernel’s package lists the CVE. Installing a fixed package changes nothing until you boot into it, and our Rocky and Ubuntu clones showed exactly that, with a newer kernel installed by cloud-init but the old one still running. Start with the running kernel on any distro.
uname -r
Then the check comes down to one command per distro family, in this order:
- Debian: grep the local changelog of the running kernel
- Ubuntu: grep
apt changelog, or runpro fix - Rocky and RHEL: ask
dnf updateinfo, then grep the RPM changelog
On Debian, the changelog of the package behind the running kernel sits under /usr/share/doc. Any count above 0 means the fix is in the kernel you booted, and 0 means it is not.
zgrep -c CVE-2026-98432 /usr/share/doc/linux-image-$(uname -r)/changelog.gz
On Ubuntu, apt changelog fetches the changelog for the package behind the running kernel from Canonical. On the newest noble kernel we could install, the count was still zero.
apt changelog linux-image-$(uname -r) 2>/dev/null | grep -c CVE-2026-98432
That box ran 6.8.0-147-generic, the current noble candidate on 31 October, and the grep printed this:
0
Rocky cloud images install kernel-core without the kernel meta-package, so rpm -q kernel answers “package kernel is not installed” and tells you nothing. Query kernel-core instead, and let dnf say which version is actually running.
rpm -q kernel-core
sudo dnf -q check-update kernel
The Rocky 10 clone had two kernels installed and was running the older one, which dnf spells out in its last two lines:
kernel-core-6.12.0-211.16.1.el10_2.0.1.x86_64
kernel-core-6.12.0-211.69.1.el10_2.x86_64
Security: kernel-core-6.12.0-211.69.1.el10_2.x86_64 is an installed security update
Security: kernel-core-6.12.0-211.16.1.el10_2.0.1.x86_64 is the currently running version
Neither of those builds fixes this CVE, though. Ask the advisory data, then the changelog of the running kernel only. Without $(uname -r), rpm reads every installed kernel-core and would count a fixed kernel you haven’t booted yet.
sudo dnf -q updateinfo list --cve CVE-2026-98432
rpm -q --changelog kernel-core-$(uname -r) | grep -c CVE-2026-98432
On both Rocky 9 and Rocky 10, updateinfo printed nothing and the changelog count was 0. The newest kernel in each repo didn’t mention the CVE either: Rocky 10’s build already sat on the clone, and we downloaded Rocky 9’s 5.14.0-687.61.1, with a changelog entry dated 27 October, and checked it with rpm -qp --changelog. An empty updateinfo result means no advisory exists yet, not that you’re safe. It also goes quiet again once you install the fix, because it only lists advisories for pending updates, so add --installed when you re-check after patching.
Rocky ships MPTCP off, Debian and Ubuntu on
Whether a program gets an MPTCP socket depends first on net.mptcp.enabled, and the default isn’t the same everywhere. Read it straight from /proc, because the Debian genericcloud image has no sysctl binary at all, and our capture script died with sysctl: command not found there.
cat /proc/sys/net/mptcp/enabled /proc/sys/net/ipv4/tcp_migrate_req
Debian 13 and Ubuntu 24.04 printed 1 and 0. Both Rocky releases printed 0 and 0, and no sysctl.d file on either system set the value, so the off default comes from the RHEL kernel build itself. The four systems compared like this on a fresh boot.
| Check | Debian 13 | Ubuntu 24.04 | Rocky 9 | Rocky 10 |
|---|---|---|---|---|
| Running kernel | 6.12.111+deb13-cloud-amd64 | 6.8.0-106-generic, then 6.8.0-147-generic | 5.14.0-611.5.1.el9_7 | 6.12.0-211.16.1.el10_2.0.1 |
| net.mptcp.enabled | 1 | 1 | 0 | 0 |
| net.ipv4.tcp_migrate_req | 0 | 0 | 0 | 0 |
ss -M works as shipped | Yes, mptcp_diag autoloads | No on the cloud image (linux-image-virtual), module is in linux-modules-extra | Yes, built in | Yes, built in |
| Default Go listener | MPTCP | MPTCP | Plain TCP | Plain TCP |
The last row is the one that matters for exposure. On Debian and Ubuntu, any Go service you run is an MPTCP listener unless someone turned it off. On Rocky it falls back to plain TCP until someone sets net.mptcp.enabled=1, so check that value before you assume a Rocky box is out of scope.
ss -M finds the MPTCP listeners
An MPTCP listener also shows up in ss -tlnp, looking exactly like a TCP one, so that view cannot answer the question. The -M flag asks the kernel for MPTCP sockets only.
sudo ss -Mlnp
On the Ubuntu box with our Go test listener running, the MPTCP view showed just that process, while sshd stayed out of it.
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 4096 *:8080 *:* users:(("golisten",pid=4285,fd=3))
An empty table with only the header line is the good result. Before you trust it on Ubuntu, though, read the next part.
Error: “modprobe: FATAL: Module mptcp_diag not found”
On Ubuntu virtual and cloud kernels, ss -Mlnp printed an empty table even with an MPTCP listener running. It does not fail loudly. The kernel answers MPTCP queries through the mptcp_diag module, which ships in linux-modules-extra, and that package isn’t installed on cloud images. Loading it by hand shows the cause.
modprobe: FATAL: Module mptcp_diag not found in directory /lib/modules/6.8.0-147-generic
Install the extra modules for the running kernel and load the module, and ss -Mlnp starts reporting real listeners.
sudo apt install linux-modules-extra-$(uname -r)
sudo modprobe mptcp_diag
If you cannot install packages on that host, count MPTCP sockets from /proc/net/protocols instead. It does not name the process, but it tells you whether one exists. Watch the IPv6 row, because a Go listener on :8080 is a dual-stack socket, so it’s counted as MPTCPv6 even though it accepts IPv4 clients.
grep -E '^MPTCP' /proc/net/protocols | awk '{print $1, $3}'
The third column is the socket count, and anything above zero means some process holds an MPTCP socket.
MPTCPv6 1
MPTCP 0
That count is what first told us the Go listener was MPTCP on Ubuntu, while ss -M was still printing nothing. If you audit a fleet with a script, check both, because a script that only parses ss -M will report every Ubuntu cloud host as clean.
Go listeners turn MPTCP on themselves
Since Go 1.24, the net package asks for MPTCP on every Linux listen socket unless you opt out, according to the Go security team advisory. You don’t need any MPTCP code in your program for this. We built the smallest possible listener to prove it on each distro, using the official Go tarball from go.dev because the golang package in Ubuntu 24.04 is older than 1.24. Create a working directory outside /tmp first.
mkdir -p ~/golisten && cd ~/golisten
vim main.go
The program does nothing MPTCP-specific. It calls net.Listen with the defaults.
package main
import (
"fmt"
"net"
)
func main() {
ln, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
fmt.Println("listening on", ln.Addr())
for {
c, err := ln.Accept()
if err != nil {
continue
}
c.Write([]byte("hello\n"))
c.Close()
}
}
Add a two-line module file next to it.
vim go.mod
The go 1.24 line matters, because Go picks its GODEBUG defaults from the version the main module declares. The GODEBUG table in the Go source lists multipathtcp as changed in 1.24 with an old value of 0, so a program whose go.mod says 1.23 or older keeps MPTCP off.
module golisten
go 1.24
Build it and start it in the background. Our first attempt built in /tmp and failed with go: warning: ignoring go.mod in system temp root /tmp, which is why the directory lives in your home. The listener binds port 8080 on every interface of a vulnerable kernel, so run it on a lab box and stop it with kill %1 when you’re done.
go build -o golisten .
./golisten &
We copied the same static binary, built with Go 1.27.3, to every system, and it gave these results:
- Debian 13: MPTCP, listed by
ss -Mlnp - Ubuntu 24.04: MPTCP, listed once
mptcp_diagwas loaded - Rocky 9 and 10: plain TCP until MPTCP was enabled
- Rocky after
sysctl -w net.mptcp.enabled=1and a restart:MPTCPv6 1
Nothing in the program changed between those runs. The kernel default decided whether you got an MPTCP listener, which means you can’t judge exposure from the source code of a Go service alone. You have to look at the running host, with the service running.
For a Go service you cannot rebuild, the runtime switch from the advisory is GODEBUG=multipathtcp=0. Under systemd, a drop-in sets it without touching the vendor unit. Ours wrapped the test binary in a golisten.service unit, so replace golisten with the name of your own Go service. Two limits apply: the drop-in replaces any GODEBUG value the unit already sets, so merge them into one line, and a program that calls ListenConfig.SetMultipathTCP(true) in code overrides the variable entirely.
sudo mkdir -p /etc/systemd/system/golisten.service.d
echo -e '[Service]\nEnvironment=GODEBUG=multipathtcp=0' | sudo tee /etc/systemd/system/golisten.service.d/mptcp-off.conf
sudo systemctl daemon-reload
sudo systemctl restart golisten
systemctl show golisten -p Environment
The unit picked up the variable, and sudo ss -Mlnp went back to an empty table with the same service still listening on 8080.
Environment=GODEBUG=multipathtcp=0
The Go team calls this per-program switch “a fragile mitigation”, since one forgotten listener undoes it, and we’d agree. It’s still the cheapest way to take a known Go service out of the proven exploit path while you wait for a kernel. If you own the source, the advisory’s build-time switch is a godebug multipathtcp=0 line in the main module’s go.mod.
MPTCP off narrows the exploit path only
So does disabling MPTCP fix CVE-2026-98432? No. Setting net.mptcp.enabled=0 host-wide is the mitigation most people are copying, and it didn’t come from a vendor. It started as a reader comment under the LWN report, while Debian, Ubuntu and Red Hat don’t mention MPTCP at all. It does have one real effect, which our lab confirmed, in that new sockets asking for MPTCP fall back to plain TCP. Persist it with a sysctl.d file.
echo "net.mptcp.enabled = 0" | sudo tee /etc/sysctl.d/90-mptcp-off.conf
sudo sysctl --system
That worked on Ubuntu, and /proc/sys/net/mptcp/enabled read 0 afterwards. On a Debian cloud image without sysctl, apply the same file through systemd, which is what reads it at boot anyway.
sudo /usr/lib/systemd/systemd-sysctl /etc/sysctl.d/90-mptcp-off.conf
Now the part the copied one-liners leave out. The sysctl doesn’t touch sockets that already exist. We set it to 0 with the Go listener running, and ss -Mlnp still listed the same PID as MPTCP.
net.mptcp.enabled = 0
LISTEN 0 4096 *:8080 *:* users:(("golisten",pid=34803,fd=3))
Only after the process restarted did it come back as plain TCP. Turning MPTCP off has four effects you need to keep apart, in this order:
- New listeners that request MPTCP silently fall back to TCP.
- Existing MPTCP listeners stay MPTCP until you restart them.
- The IPv4 race in
tcp_v4_syn_recv_sock()is still there for every TCP listener. - The migration path through
tcp_migrate_reqisn’t affected either way.
So you leave the one exploit anyone has demonstrated, and you stay inside the bug. That trade is worth making on a host that runs Go services and can’t reboot today, and it’s close to pointless on a Rocky box that already ships with MPTCP off. If you take this step, restart every service that listens (or reboot) and re-run ss -Mlnp, otherwise you’ve only changed a number in /proc. Then plan the kernel upgrade as if you’d done nothing.
Containers get their own MPTCP switch
The sysctl lives in each network namespace, and the host file does not reach into containers that have their own. We set the host to 0 on Ubuntu, created a fresh namespace the way a container runtime does, and read the value inside it.
sudo ip netns add ctr1
sudo ip netns exec ctr1 cat /proc/sys/net/mptcp/enabled
sudo ip netns delete ctr1
Inside the new namespace, MPTCP was on, while the host itself read 0:
1
On Rocky 10, the same test printed 0 inside the new namespace, matching its host default. That has two consequences on Debian and Ubuntu hosts running Docker or Kubernetes. Running ss -Mlnp or reading /proc/net/protocols on the host only shows the host namespace, so audit each container from inside its own namespace. And turning MPTCP off for a container means setting it per container, for example with Docker’s --sysctl net.mptcp.enabled=0, since the host file won’t do it for you. Containers on --network=host share the host namespace, so the host file does cover those. On Kubernetes, net.mptcp.enabled isn’t in the safe sysctl set, so a pod securityContext.sysctls entry also needs the kubelet to allow it as an unsafe sysctl.
For a Docker container, look up its PID and run ss inside its network namespace, swapping web for the container name:
sudo nsenter -t "$(sudo docker inspect -f '{{.State.Pid}}' web)" -n ss -Mlnp
We ran our Go listener in a busybox container on the Ubuntu host while the host sysctl read 0, and the container’s namespace still held an MPTCP listener:
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 4096 *:8080 *:* users:(("golisten",pid=10728,fd=3))
Restarting the same container with --sysctl net.mptcp.enabled=0 left only the header line in that view. An empty table means no MPTCP listener in the container, provided the host kernel has mptcp_diag loaded as described earlier.
Debian takes the fix in one package
The Debian 13 system here ran the official genericcloud image from 15 October under KVM, which still booted the vulnerable 6.12.111 kernel. That gave us a real before and after. Refresh the package lists and check whether a kernel upgrade is waiting.
sudo apt update
apt list --upgradable 2>/dev/null | grep linux-image
The fixed build comes from trixie-security, so a system without the security suite in its sources won’t see it.
linux-image-cloud-amd64/stable-security 6.12.113-1 amd64 [upgradable from: 6.12.111-1]
Upgrade the kernel meta-package your system uses. Cloud images use linux-image-cloud-amd64, and dpkg -l 'linux-image-*' shows which one you have. Then reboot, because the new kernel does nothing until it runs.
sudo apt-get -y install linux-image-cloud-amd64
sudo systemctl reboot
Before the reboot, uname -r still said 6.12.111 and /run/reboot-required existed, which is the state many patched-on-paper servers sit in for weeks. After it, the running kernel and its changelog both confirm the fix.

apt-get autoremove left the old 6.12.111 kernel in place, because apt protects recent kernels from autoremoval on purpose. Remove it by name once the new one has booted cleanly, and remember that this removes your only fallback kernel, so keep it a day longer if the host has out-of-tree modules you still need to test.
sudo apt-get purge linux-image-6.12.111+deb13-cloud-amd64
Debian 12 follows the same steps with different packages. The stock linux kernel moves to 6.1.190-1 (DLA-4841-1), and hosts on the linux-6.12 backport move to 6.12.113-1~deb12u1 (DLA-4850-1). We didn’t run bookworm in this lab, so check those versions against the tracker before you roll them out. Our PHP2Shell patch guide for Debian uses the same changelog check for userland packages.
Ubuntu and Rocky wait on a kernel
Until a fixed kernel exists, the useful work on Ubuntu and Rocky is knowing the moment it lands. Watch for these signals, in the order they usually appear:
- A changed status on the Ubuntu or Red Hat tracker
- A USN for
linux, or an RHSA followed by a Rocky RLSA - The changelog grep printing 1 after your reboot
The Ubuntu Pro client checks one CVE against the installed packages, and it doesn’t need a Pro subscription for the check. Our 24.04 box wasn’t attached to one.
pro fix CVE-2026-98432
After printing the CVE description, it ended with a plain verdict and exit code 1.
1 affected source package is installed: linux
(1/1) linux:
A fix is coming soon. Try again tomorrow.
1 package is still affected: linux
✘ CVE-2026-98432 is not resolved.
That exit code makes it easy to use in a monitoring check, but run pro fix --dry-run CVE-2026-98432 there instead (it printed the same verdict and exit code 1 for us), because plain pro fix tries to install the fix once one exists. The Ubuntu tracker lists 6.8.0-149.149 next to the noble work-in-progress status for the generic linux kernel. Cloud kernels such as linux-aws and linux-azure have their own version lines on the same page, so watch the one you run. We didn’t test Livepatch here, so we can’t tell you whether a live patch will arrive before the kernel. For the routine side of patching noble, the Ubuntu PHP2Shell walkthrough covers the same apt flow.
On Rocky, the kernel packages come from the BaseOS repo, which our Rocky Linux 10 repo guide maps out next to the SIG repos. dnf can filter an upgrade down to one CVE. Today it finds nothing, which is the honest answer.
sudo dnf upgrade --cve CVE-2026-98432
When Rocky publishes an advisory, the same command will pull the fixed kernel-core, and the changelog grep from earlier will print 1. Until then, Rocky 9 resolved it to an empty transaction, with a first line that reads like a clean bill of health and isn’t one:
No security updates needed, but 218 updates available
Dependencies resolved.
Nothing to do.
Complete!
Remember the Rocky default from earlier. With net.mptcp.enabled at 0, a stock Rocky server is outside the proven exploit unless someone enabled MPTCP, but it’s still inside the bug. Check the value, check ss -Mlnp, and reboot the moment the kernel lands. Our RHEL and Rocky patch guide shows the dnf side of that, and the nginx CVE walkthrough uses the same check-then-patch layout for a userland bug.
Red Hat’s filter drops TCP with IP options
The race needs a SYN that carries IPv4 header options, which is the field ip_options_build() reads after the free. A Go maintainer first floated dropping those packets on the Go issue without confirming it, and on 30 October Red Hat published the same idea as the official mitigation in RHSB-2026-016. Red Hat is clear that it reduces exposure but “cannot fully prevent it” and is “not a substitute for patching”. We ran the bulletin’s rule as written and tested it from a second host.
The table hooks input at priority -310, ahead of the usual firewall chains, and drops any TCP packet whose IPv4 header is longer than the 20-byte minimum. An IHL of 5 means no options. Create the file on the server.
vim cve-2026-98432.nft
Paste the table from the bulletin:
table inet cve_2026_98432 {
chain input {
type filter hook input priority -310; policy accept;
ip protocol tcp ip hdrlength > 5 counter drop
}
}
Validate it before loading it, then load it. The check exited 0 on our Ubuntu server and the table went in without touching the existing rules.
sudo nft --check --file cve-2026-98432.nft
sudo nft --file cve-2026-98432.nft
From the client, a short Python script opens one TCP connection with four bytes of IP options set through the ordinary IP_OPTIONS socket option, and one without. Save it on the second host.
vim ipopt.py
The options are three NOPs and an end-of-list marker, so the packet is valid but carries a 24-byte header.
import socket, sys
host, port, opts = sys.argv[1], int(sys.argv[2]), sys.argv[3] == "opts"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if opts:
s.setsockopt(socket.IPPROTO_IP, socket.IP_OPTIONS, b"\x01\x01\x01\x00")
s.settimeout(5)
try:
s.connect((host, port))
print("connected", "with IP options" if opts else "without IP options")
except OSError as e:
print("failed", "with IP options:" if opts else "without IP options:", e)
Point it at the SSH port on the server, once with options and once without.
python3 ipopt.py 10.0.1.50 22 opts
python3 ipopt.py 10.0.1.50 22 plain
Without the table, both connections succeeded. With it loaded, the option-bearing SYN timed out and the plain one went through.
failed with IP options: timed out
connected without IP options
The counter on the server confirms the kernel dropped that one attempt’s SYN and its retransmissions before TCP saw them.
sudo nft list table inet cve_2026_98432
Look for the drop count at the end of the rule line. nft prints the priority back as raw - 10, which is the named form of -310.
table inet cve_2026_98432 {
chain input {
type filter hook input priority raw - 10; policy accept;
ip protocol tcp ip hdrlength > 5 counter packets 5 bytes 320 drop
}
}
An ICMP ping with the record-route option still got through, because the rule matches TCP only. A broader rule without ip protocol tcp, which we tried first, dropped those pings too and would also catch IGMP, whose packets carry a router-alert option. Keep these limits in mind before you roll it out:
- It’s runtime only, so any reboot before the fixed kernel ships drops it
- It hooks input, so traffic forwarded to bridge-networked containers bypasses it
- CIPSO and other labelled networking hosts use IP options, so the rule breaks them and likely doesn’t protect them; patch those first
What our test proves is narrow: the filter stops option-bearing SYNs from reaching the TCP stack on the host. It doesn’t prove that every exploit variant needs IP options, and Red Hat doesn’t claim that either. Use it on hosts you can’t patch yet, reload it after any reboot, and once the fixed kernel is running, remove it with sudo nft delete table inet cve_2026_98432.