
Idempotent shell script that installs a persistent iptables rule dropping IPv4 TCP packets with IP options to mitigate CVE-2026-98432 on Ubuntu and Debian until a patched kernel is available.
A single idempotent script that drops incoming IPv4 TCP packets carrying IP options, keeps the rule across reboots, and checks that it works. It is meant for Ubuntu (18.04 – 24.04) and Debian (11 – 13) servers that can't get a fixed kernel yet.
This is a stopgap, not a fix. The only real fix is a patched kernel plus a reboot. Remove this mitigation once the server runs a fixed kernel.
curl -fsSL https://raw.githubusercontent.com/Mervent/cve-2026-98432/master/install.sh | sudo sh
You can run it any number of times: the files are overwritten and the rule is never duplicated. At the end the script validates the result and exits non-zero on any failure:
--- validation ---
OK helper installed: /usr/local/sbin/cve-2026-98432-mitigation
OK cron entry: /etc/cron.d/cve-2026-98432
OK cron service enabled
OK iptables rule active (raw/PREROUTING)
OK exactly one rule (no duplicates)
plain SYN: connected, SYN with IP options: timeout
OK drop test: packets with IP options are dropped
--- rule counters ---
pkts bytes target prot opt in out source destination
3 204 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 u32 "0x0>>0x18&0xf=0x6:0xf" /* cve-2026-98432 */
| Path | Purpose |
|---|---|
/usr/local/sbin/cve-2026-98432-mitigation | Helper that holds the rule. With no argument it adds the rule if it's missing. --check exits 0 if the rule is active. --remove deletes it. |
/etc/cron.d/cve-2026-98432 | @reboot entry that re-applies the rule after every boot |
The rule itself:
iptables -t raw -I PREROUTING -p tcp -m u32 --u32 "0>>24&0xF=6:15" \
-m comment --comment cve-2026-98432 -j DROP
sudo /usr/local/sbin/cve-2026-98432-mitigation --check && echo active
sudo iptables -t raw -L PREROUTING -v -n | grep cve-2026-98432
sudo /usr/local/sbin/cve-2026-98432-mitigation --remove
sudo rm /usr/local/sbin/cve-2026-98432-mitigation /etc/cron.d/cve-2026-98432
To see whether your distribution has shipped a fix, check
Ubuntu or Debian
(for Debian 9 – 11, the Freexian ELTS tracker).
Once your release shows "Fixed", run apt update && apt full-upgrade, reboot, then remove the mitigation.
As of November 1, 2026, Debian 12 (linux 6.1.190-1, DLA-4841-1) and Debian 13 (linux 6.12.113-1,
DSA-6568-1) already have fixed kernels, so on those releases upgrade instead of using this script.
Debian 11's fix (linux 5.10.272-1, ELA-1846-1) is only in Freexian's ELTS repository: commercial,
but free on request for individuals and small non-profits.
CVE-2026-98432 ("ipv4: free inet_opt and ireq_opt after an RCU grace period") is a use-after-free in the IPv4 TCP handshake. It affects Linux 4.4 and later and is rated CVSS 9.8.
If a SYN carries IPv4 options, the kernel saves them on the request socket so it can echo them in
the SYN-ACK. tcp_v4_syn_recv_sock() then hands that buffer to the child socket without copying it.
When the child socket dies, the buffer is freed with a plain kfree(), while another CPU may still
be reading it to build a SYN-ACK for a retransmitted SYN.
All of this happens in the kernel before any application sees the connection. Any listening IPv4 TCP port is reachable this way (SSH, HTTP, PostgreSQL and so on), and no credentials are needed. Anthropic reported a working remote-root exploit against hosts that have a multipath TCP (MPTCP) listener. The Go Security Team notes that the bug is not specific to MPTCP.
The memory that gets freed too early exists only when the incoming SYN carries IPv4 options. With no options there is no saved buffer, so the use-after-free has nothing to act on. Legitimate TCP traffic practically never carries IPv4 options, so dropping those packets costs nothing in practice. Red Hat (RHSB-2026-016) and AlmaLinux publish an equivalent nftables rule.
u32 "0>>24&0xF=6:15" reads the IHL field, the IPv4 header length in 32-bit words. A value of 5 is
the bare 20-byte header. Values from 6 to 15 mean options are present.
Red Hat states that such a rule "reduces exposure to this vulnerability but cannot fully prevent it". Treat it as risk reduction until the kernel is patched.
raw / PREROUTINGPREROUTING sees every incoming packet, both traffic to the host and traffic forwarded to Docker
containers on published ports. A rule in INPUT, which is where ufw puts its rules, would miss
the forwarded traffic.raw table runs before connection tracking, so dropped packets never create conntrack entries.raw/PREROUTING, so the rule survives their restarts.iptables is present on every Ubuntu target release. On Ubuntu 18.04 and 20.04 it uses the legacy
backend; from Ubuntu 22.04 and on Debian 11+ it is iptables-nft. The nft binary isn't installed
by default everywhere. On Debian, iptables itself may be missing; the script then asks you to run
apt install iptables.iptables-nft, ufw/Docker and this rule share the nf_tables backend, so one rule covers both.u32 match needs the xt_u32 kernel module. If it is missing, the script fails and tells you
to check modinfo xt_u32.@reboot entrynftables.service. On Ubuntu /etc/nftables.conf starts with flush ruleset, and the
service runs nft flush ruleset on stop. Either one wipes ufw and Docker rules.iptables-persistent. netfilter-persistent save dumps every current rule, Docker's
included, and restoring that snapshot at boot conflicts with the rules Docker creates itself.before.rules. It only works when ufw is enabled, and its chains don't see forwarded
traffic to containers./etc/cron.d is idempotent by
overwrite, and removing it is one rm. The trade-off is a window of a few seconds after boot when
the network is up but cron hasn't applied the rule yet. That is acceptable for a mitigation that
only needs to last until the next kernel update.net.mptcp.enabled=0Disabling MPTCP removes the precondition of the one published exploit, not the bug. Plain TCP
listeners still go through the same vulnerable code. On a server without MPTCP listeners
(ss -Mlnp prints nothing) the sysctl changes nothing at all. It is a harmless extra, not a
substitute for this rule.
The script checks that the helper and the cron entry are installed, that cron is enabled, and that
exactly one rule is active. It then runs an end-to-end drop test with python3, skipped if python3
is missing:
127.0.0.1.Loopback traffic goes through raw/PREROUTING, so this proves the rule actually drops packets and
isn't merely present in the table.