
Temporary mitigation for CVE-2026-98432 (Linux IPv4 TCP ireq_opt use-after-free): drop IPv4 TCP with IP options, disable MPTCP. Tested scripts + verification. EN/KO.
This repository holds scripts that drop IPv4 TCP packets carrying IP options on a Linux host. On hosts without SELinux/Smack NetLabel CIPSO labeling, CVE-2026-98432 (a Linux kernel IPv4 TCP use-after-free) cannot trigger without such packets. It is a temporary mitigation, not a fix. It was not tested against a real exploit (there is no public PoC), and no vendor endorses it. If your distribution already ships a fixed kernel, install that, and run revert.sh if you applied this. If it does not, check that the mitigation applies to your host, then apply and verify it with the steps below (about 10 minutes). The author is an individual administrator, not a vendor.
uname -r with the fixed stable versions: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3 (fix commit e3f33b0a1d89d738e2b913dab519226eaf76e15b). A distribution kernel may carry the fix under a different version number, so also check your vendor's tracker.cat /sys/kernel/security/lsm. If SELinux or Smack is listed and you use NetLabel with a CIPSOV4 mapping, this mitigation does not cover that path.nft. OpenWrt has its own path (see Files). Hosts without systemd, other than OpenWrt, are not covered.Severity: the kernel CNA gives CVSS 9.8. Red Hat, Oracle and SUSE give 8.1, and Amazon gives 7.0. Anthropic publicly described a remote root exploit against Linux servers with an MPTCP listener (2026-10-27). No in-the-wild exploitation was reported as of 2026-10-29.
Distribution status as of 2026-10-29/30 (a snapshot, so check your vendor):
| Distribution | Status |
|---|---|
| Ubuntu (all supported releases) | no fixed kernel |
| RHEL 8/9/10 | no fixed kernel |
| Proxmox VE | pve-kernel changelog had no entry for this CVE on 2026-10-30 |
| Debian, Oracle Linux UEK, some SUSE, some Amazon Linux | fixes available |
Run sudo ./mitigate.sh. It is idempotent (running it again reloads the ruleset). It installs the files listed under Files, and it exits if you are not root, if nft is missing, or if systemd is missing.
Compare the output with the reference below. The first line must be:
svc=active enabled=enabled mptcp=0
The two rules follow it, one in the inet table and one in the bridge table.
If a service listens with MPTCP, restart it. net.mptcp.enabled=0 affects new sockets only, so an already-open MPTCP listener stays MPTCP until its service restarts. The sysctl is per network namespace, and mitigate.sh sets it for the host namespace only.
If the host runs LXC or Docker containers, continue with Containers.
The published exploit targeted MPTCP listeners. The race itself does not require MPTCP (inference from the fix description). Whether a host without MPTCP can be fully compromised is not established.
The target's SYN-ACK echoes the IP options. A client that itself runs this mitigation drops that SYN-ACK, so check-blocked.py reports "blocked" even when the target is unmitigated. Measured on one host: after revert.sh on the target, check-blocked.py from a mitigated client still printed ipopt FAIL TimeoutError, while verify-synack.sh showed ipopt synack=5.
Pick one tool:
python3 check-blocked.py <host> <port> there (no root needed). It connects twice: plain, then with an IPv4 Record Route option set through the IP_OPTIONS socket option.sudo ./verify-synack.sh <ip> <port> on any client (root, tcpdump and python3 needed on the client). It sends a plain SYN and an IP-options SYN from fixed source ports and counts the target's SYN-ACKs with tcpdump.Then compare the output with the table for that tool.
check-blocked.py (from a client without the mitigation):
| Output | Meaning |
|---|---|
plain CONNECTED | normal TCP works |
ipopt FAIL TimeoutError | the IP-options SYN was dropped, as intended |
verify-synack.sh:
| Output | Meaning |
|---|---|
plain: CONNECTED synack=N | ipopt: TimeoutError synack=0 | target is mitigated |
ipopt ... synack>=1 | target is not mitigated (the IP-options SYN was answered) |
Kernel-level result (one Proxmox VE host, kernel 7.0, 2026-10-30): with the mitigation off, the vulnerable code path ran once per path, over WireGuard and LXC to LXC. With it on, the SYN timed out and the path ran 0 times. The sample is 2 paths in 2 states on one host. The tracing method is in docs/ANALYSIS.md (English).
nftables state is per network namespace, so host rules alone do not protect container namespaces. Measured on LXC containers: with only host rules, an IP-options SYN from inside a container to its own 127.0.0.1 or its own IP connected. Containers share the host kernel, so code inside any container could reach the vulnerable path this way.
sudo ./inject-netns.sh on the host. It loads the same ruleset into every running LXC container (via pct/lxc-info, Proxmox) and every running Docker container (host-network containers are skipped).| Output | Meaning |
|---|---|
ok lxc:<id> or ok docker:<id> | ruleset loaded in that container namespace |
injected=N failed=M | totals, M should be 0 |
The injection is not persistent. It is lost when a container restarts, so re-run the script after restarts. Docker containers nested inside an LXC container need the script run inside that LXC container (not measured).
Measured result: across 5 Proxmox hosts, 64 container namespaces were injected with 0 failures. After injection, the same test timed out and the container namespace's drop counter rose.
The symptom of this mitigation interfering is a TCP connection that hangs (times out) rather than being refused, together with a rising counter in the output of:
nft list ruleset | grep counter
| Command | Effect |
|---|---|
systemctl stop cve-2026-98432-mitigation | off immediately, comes back on at reboot |
systemctl disable --now cve-2026-98432-mitigation | off now and across reboots |
Compatibility measured on the tested hosts: the rules sit in their own tables and coexisted with Docker, ufw, iptables-legacy NAT rules, and NetBird (WireGuard) routing. Normal TCP connections kept working on every tested path. Drop counters stayed at test-packet counts during normal operation (no legitimate traffic matched) over a short observation window (hours, not days).
Inference, not measured: a nftables.service whose config contains flush ruleset would delete the tables when it reloads. Check for that, and re-run mitigate.sh after such a reload.
uname -r.sudo ./revert.sh. Add --mptcp if you also want MPTCP re-enabled.| Output | Meaning |
|---|---|
remaining tables: 0 | the unit is disabled, the three files and both tables are gone |