A CVE-2026-98432 firewall rule for Ubuntu, with or without Docker

PhotoStructure

4 min read Original article ↗

A CVE-2026-98432 firewall rule for Ubuntu, with or without Docker

CVE-2026-98432 is a use-after-free in the kernel’s handling of IPv4 TCP connections with IP options. Ubuntu rates it High; as of November 1, 2026, its tracker listed the Ubuntu 26.04 linux package as vulnerable, with a fix in progress for 7.0.0-43.43. Red Hat’s advisory recommends a temporary filter that drops incoming IPv4 TCP packets with IP options, using an nftables rule on the input hook.

This reduces exposure; it doesn’t fix the kernel bug or prevent every way of triggering it. Install and boot a fixed kernel when one is available for your kernel package. IP options are separate from ordinary TCP options, which these rules leave alone. Applications that need IPv4 options over TCP will stop working on the filtered paths.

Limits

These rules don’t cover, or we didn’t test:

  • Any network namespace other than the host’s: a process connecting to a container’s own loopback, or a local user who can create a network namespace (unshare -rn).
  • IPv6. Ubuntu says the main issue doesn’t affect it, but notes a separate request-socket migration issue involving CALIPSO options. These IPv4 rules don’t address that issue.
  • Other Docker network modes and Docker’s nftables firewall backend are untested here; we tested bridge networking with the default iptables backend.

Which rule you need

The table compares filtering of incoming IPv4 TCP packets with IP options, not complete protection against the vulnerability.

Traffic pathRed Hat’s input ruleUFW one-linerprerouting rule below
To a service on the hostdropsdropsdrops
Forwarded to a Docker bridge container’s published portmisses itmisses itdrops

If UFW is enabled and you only need to filter traffic delivered to the host, add this line to /etc/ufw/before.rules immediately after # End required lines, before any ACCEPT rules, then run sudo ufw reload. Delete it and reload to remove it. This rule doesn’t filter forwarded traffic, whether Docker is involved or not.

-A ufw-before-input -p tcp -m u32 --u32 "0>>24&0x0F=6:15" -m comment --comment "CVE-2026-98432" -j DROP

The rule

This table hooks prerouting, which also sees forwarded traffic, and output, which filters locally generated packets, including host connections to a container’s address. It lives in its own table; UFW reloads and Docker restarts left it intact in our tests.

destroy table inet cve_2026_98432
table inet cve_2026_98432 {
	chain prerouting {
		type filter hook prerouting priority -310; policy accept;
		ip protocol tcp ip hdrlength > 5 counter drop comment "CVE-2026-98432"
	}
	chain output {
		type filter hook output priority -310; policy accept;
		ip protocol tcp ip hdrlength > 5 counter drop comment "CVE-2026-98432"
	}
}

destroy table needs nftables 1.0.7 and kernel 6.3 or later, so the table needs Ubuntu 24.04 or later. We tested it on 26.04. Ubuntu 22.04’s nftables 1.0.2 rejects it with a syntax error.

apply-cve-2026-98432-mitigation.sh installs it as /etc/cve-2026-98432.nft with a systemd unit that loads it before UFW and Docker at boot. The script requires nft and refuses to run while nftables.service is active: a configuration containing flush ruleset would erase this table too. Check that no other firewall loader will flush it at boot or on reload.

rollback-cve-2026-98432-mitigation.sh removes the separate table and service once you’ve booted a fixed kernel. It doesn’t remove the UFW one-liner above. Read the scripts before running them with sudo bash. SHA-256:

6c1d850a3f811f7bdaff723dc9075dce4b37b7085a71a46d40c7903054935bbe  apply-cve-2026-98432-mitigation.sh
17b33db29258698e80af417b6465fcaf4a4ee68241325f2d4445ec4e2e5df4eb  rollback-cve-2026-98432-mitigation.sh

ufw status won’t show it; sudo nft list table inet cve_2026_98432 shows it and its drop counters.

Testing

On a disposable Ubuntu 26.04 VPS, we used runtest.sh to send plain and IP-options HTTP requests from a network namespace to a host listener and to a Docker-published port. It also checks connections originating on the host. The client, ipopt_client.py, uses an ordinary socket with IP_OPTIONS set; it isn’t an exploit. With this table loaded, plain requests got HTTP 200 responses and every options request was dropped, including after ufw reload, a Docker restart, and a reboot. These checks verify packet filtering, not resistance to an exploit.

The test script expects listeners, a container, and the client file to be set up as described in its header. It creates a network namespace and virtual interfaces and leaves them in place. Run it on a disposable host and inspect the results and drop counters; it doesn’t assert pass or fail.

Use a network namespace on the test host to avoid upstream filtering. First confirm that both plain and options requests connect without the mitigation; then apply it and check that only the options requests fail and the drop counters increase. Options packets we sent from outside, from home and from two other Hetzner servers, were dropped before they reached the target, even with no rule loaded, so a timeout from outside proves nothing about this rule.