↓ Skip to main content
  1. Posts/

CVE-2026-98432: Linux TCP Use-After-Free. Find It, Mitigate It, Auto-Remove It with Fleet

Author
Dhruv Majumdar
Two decades at the seam between detection theory and operational reality. Notes on MxDR, VMDR, threat intel, red teaming — what the vendor said versus what the host actually did.
Table of Contents
TL;DR. CVE-2026-98432 is a kernel race in IPv4 TCP connection setup. A remote, unauthenticated SYN carrying IP options can make the kernel read freed memory. Ubuntu and RHEL have no fixed kernel yet; Debian, Oracle UEK and Amazon Linux do. Until yours ships, run cve-2026-98432-mitigate.sh from a Fleet policy. The same script removes the mitigation once the host boots a patched kernel.

What it is
#

tcp_v4_syn_recv_sock() gives the new child socket the request socket’s IP options (ireq_opt) without copying them. A retransmitted SYN for the same request can then be processed on another CPU while the child is freed. The child’s inet_opt is freed with a plain kfree(), so the SYNACK builder reads freed memory in ip_options_build(). The fix switches both frees to kfree_rcu() (kernel commit e3f33b0a1d89).

Four-step diagram of CVE-2026-98432. Step 1: a remote IPv4 TCP SYN carrying IP options with IHL above 5. Step 2: tcp_v4_syn_recv_sock hands ireq_opt to the child socket without a copy. Step 3: CPU A frees the child with plain kfree while CPU B processes a retransmitted SYN and still reads ireq_opt. Step 4: use-after-free in ip_options_build. Below, an nftables rule dropping IPv4 TCP with IP options cuts step 1, net.mptcp.enabled=0 removes the exploited listener type at step 2, and kfree_rcu is the real fix at step 3.
Where the race fires and where each control cuts it. The nftables rule and the sysctl are interim; only the kernel update closes the bug.

Two conditions matter:

  • IP options. In practice ireq_opt is non-NULL only when the SYN header has options (IHL > 5), or when SELinux/Smack NetLabel uses CIPSO, per the community mitigation write-up. Ordinary traffic does not carry options.
  • IPv4 only. IPv6 copies the options and is not affected by the main race. A related race exists with net.ipv4.tcp_migrate_req=1 or a BPF SK_REUSEPORT migrate program (Ubuntu CVE page).

The intel
#

Date (2026)Event
Oct 5Upstream fix applied
Oct 15CVE published
Oct 24Kernel CNA adds CVSS 9.8 (AV:N/AC:L), assuming an attacker who resends the SYN to win the race
Oct 27Anthropic publishes the exploit write-up
Oct 29Ubuntu and RHEL still have no released fix

Sources: The Hacker News, Anthropic.

Anthropic says Claude wrote an exploit that gives a remote attacker with no credentials root on a Linux server with a multipath TCP (MPTCP) listener: a kernel address leak in 48 minutes, command execution five minutes later. The post does not include the exploit, the kernel version or the configuration tested. The CVE record and the fix never mention MPTCP, so treat MPTCP as the path Anthropic used, not as a precondition.

Scores disagree, and have moved. The kernel CNA says 9.8. On Oct 29 The Hacker News reported Oracle and SUSE at 8.1, Amazon at 7.0, and Red Hat at 5.9 on its CVE page but 8.1 in its advisory file. Red Hat’s page now shows 9.8 with attack complexity Low, still marked preliminary, and describes the impact as a crash or possible memory corruption (Red Hat). No exploitation had been reported as of Oct 29, and the bug was not in the CISA KEV copy CIRCL updated on Oct 28, per The Hacker News.

Who is affected
#

Linux 4.4 and later with an IPv4 TCP listener. Upstream fixes: 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10, 7.3. Distribution state on Oct 29:

DistributionState
UbuntuNo released kernel. 22.04 to 26.10 work in progress (24.04 target 6.8.0-149.149, 26.04 target 7.0.0-43.43); 16.04 to 20.04 listed vulnerable (tracker)
RHEL 8, 9, 10Affected, no fix released. RHEL 7 not affected
Debian 12 / 13Fixed: 6.1.190-1 (DLA-4841-1) / 6.12.113-1 (DSA-6568-1) (tracker)
Oracle Linux UEK, Amazon Linux 2023Fixed for some kernels, e.g. kernel6.18-6.18.56-125.164.amzn2023 (ALAS2023-2026-3251)

Go programs listen with MPTCP by default since Go 1.24, per the Go Security Team as relayed by The Hacker News. A Go service on an unpatched host is the shape of target Anthropic describes.

Rush, or not
#

My assessment, not vendor guidance.

Rush (hours)Plan it (days)
Internet-facing or partner-reachable hosts with any IPv4 TCP listenerHosts reachable only from a network segment you control
Go services and anything else that opens MPTCP listenersIPv6-only exposure
Hosts with tcp_migrate_req=1Debian, Oracle, Amazon hosts: install the fixed kernel instead of mitigating

No public exploit, no KEV entry, and a race to win keep this out of “drop everything” for internal-only fleets. The window is the gap between a working exploit existing and your vendor shipping a kernel.

Find it with Fleet
#

Software and Vulnerabilities first. Fleet inventories deb_packages and rpm_packages hourly. Search Vulnerabilities for CVE-2026-98432; hosts running affected linux-image-* packages show up once the CVE is matched. That answers “who runs a vulnerable kernel”.

Then a live query for exposure. Run on Linux hosts. This is cheap: no package scan.

SELECT k.version AS running_kernel,
       o.version AS os_version,
       (SELECT current_value FROM system_controls WHERE name = 'net.mptcp.enabled') AS mptcp_enabled,
       (SELECT current_value FROM system_controls WHERE name = 'net.ipv4.tcp_migrate_req') AS tcp_migrate_req
FROM kernel_info k, os_version o;

mptcp_enabled = 1 is the path Anthropic exploited; tcp_migrate_req = 1 adds the migration race. Pair it with Fleet’s listening-ports data to see which IPv4 TCP services are reachable.

Live queries answer slowly: distributed results often take longer than 90 seconds, so wait before concluding a host is silent. Keep anything you will run on every host cheap. Scanning deb_packages repeatedly can trip osquery’s watchdog.

Mitigate until the kernel ships
#

cve-2026-98432-mitigate.sh applies two controls on Ubuntu and keeps them across reboots with one systemd unit:

  1. nftables ip protocol tcp ip hdrlength gt 5 counter drop in a prerouting chain at priority -310. This stops the SYNs that carry options.
  2. sysctl net.mptcp.enabled = 0. Listeners that are already open keep MPTCP until their service restarts.

Based on a community mitigation (typhoon1217/cve-2026-98432-mitigation). Limits:

  • It is unvendored and untested against a real exploit; no public exploit is known (Anthropic did not publish its own). Red Hat says no mitigation meets its criteria.
  • It covers the host network namespace. Docker NAT traffic to published ports is dropped before it reaches a container, but containers with their own NIC (macvlan, ipvlan), traffic between containers on one bridge, and the SELinux/Smack CIPSO path are not covered.
  • The unit is PartOf=nftables.service, so restarting nftables re-applies the rule. A reload that flushes the whole ruleset does not; restart cve-2026-98432-mitigation afterwards. osquery cannot see the live ruleset, so the policy trusts the unit state.
  • It drops any IPv4 TCP that legitimately carries IP options. That is rare; watch the counter in nft list table inet cve_2026_98432.

Run it by hand to canary it: upload under Controls > Scripts, then Hosts > host > Actions > Run script, or fleetctl run-script --host <name> --script-path cve-2026-98432-mitigate.sh. Verify with osquery, which cannot read nftables but can see the unit, the files and the sysctl:

SELECT (SELECT current_value FROM system_controls WHERE name = 'net.mptcp.enabled') AS mptcp_enabled,
       (SELECT active_state || '/' || sub_state || '/' || unit_file_state
        FROM systemd_units WHERE id = 'cve-2026-98432-mitigation.service') AS unit_state,
       (SELECT COUNT(*) FROM file WHERE path = '/etc/cve-2026-98432.nft') AS nft_file_present;

Expected: 0, active/exited/enabled, 1. The script’s own check reads the live rule.

Policies: find the gaps, fix them on check-in
#

A policy checks every host on a schedule, and a policy automation can run a script on the hosts that fail it. cve-2026-98432-policies.yml defines two policies that share the one script:

PolicyPasses whenOn failure
Patched or mitigatedRunning kernel has the fix, or the unit is active with MPTCP offScript applies the mitigation
Mitigation removed after patchNot (patched kernel and mitigation files still present)Script removes the mitigation
- name: CVE-2026-98432 - Ubuntu kernel patched or mitigated
  platform: linux
  critical: true
  query: |
    SELECT 1 FROM os_version
    WHERE platform != 'ubuntu'
       OR EXISTS (
         SELECT 1 FROM os_version o, kernel_info k
         WHERE (o.major = 24 AND k.version LIKE '6.8.0-%-generic'
                AND CAST(substr(k.version, 7) AS INTEGER) >= 149)
            OR (o.major = 26 AND k.version LIKE '7.0.0-%-generic'
                AND CAST(substr(k.version, 7) AS INTEGER) >= 43))
       OR ((SELECT current_value FROM system_controls WHERE name = 'net.mptcp.enabled') = '0'
           AND EXISTS (SELECT 1 FROM file WHERE path = '/etc/cve-2026-98432.nft')
           AND EXISTS (SELECT 1 FROM systemd_units
                       WHERE id = 'cve-2026-98432-mitigation.service' AND active_state = 'active'));
  run_script:
    path: ../lib/cve-2026-98432-mitigate.sh

The kernel check compares the ABI number in kernel_info.version (6.8.0-149-generic gives 149), which avoids scanning deb_packages on every host. Only -generic kernels on 24.04 and 26.04 are recognised; HWE, cloud and low-latency kernels count as unpatched, so they keep the mitigation. The failing-host list on the policy page is your work queue.

How Fleet runs it, per the policy automation docs:

  • The script runs when the policy newly fails on a host. A host that stays failing does not re-trigger it, and a failed run is retried up to 3 times, reset once the host passes.
  • Policies run hourly by default, so a new host is contained within about an hour of its first run.
  • Script automation on a policy is Fleet Premium, fleet-level policies only, not global ones.
  • The script must be defined in the same fleet as the policy, and fleetd needs --enable-scripts (on by default with MDM).
  • Editing the script’s content does not re-run it. Reset the policy from its Automation runs tab, or change the query.

Enable through the UI under Policies > Manage automations > Run script, or commit the YAML and let fleetctl gitops apply it.

When the patch lands
#

  1. Ubuntu publishes the kernel. Confirm the version against the tracker and, if it differs from 6.8.0-149.149 or 7.0.0-43.43, edit fixed_for() in the script and the two numbers in the policy queries. The shipped values are Ubuntu’s work-in-progress targets, not a released fix. Only 24.04 and 26.04 -generic kernels are recognised: 22.04, 26.10, HWE and cloud kernels keep the mitigation until you add them.
  2. Patch and reboot. Until the reboot the running kernel is still the old one, so the mitigation correctly stays.
  3. The host boots the fixed kernel. Patched or mitigated still passes. Mitigation removed after patch now fails and runs the same script, which sees a fixed kernel and takes the mitigation out. Both pass on the next run.

To remove it by hand at any time, run cve-2026-98432-mitigate.sh revert on the host. status reports the kernel and mitigation state without changing anything.

Related

Pre-CVE Threat Response: A Dirty Frag Walkthrough with Fleet

Vulnerability management isn’t CVE management. When a public exploit lands before NVD has caught up, traditional vuln scanners return empty and incident response stalls waiting for a row in a database. This is a worked example of using Fleet’s primitives — live osquery, run-script, policies — to investigate, scope, mitigate, and verify based on the artifacts of the threat instead of its catalog representation.

HTTP2Shell (CVE-2026-111497): Hunt Vulnerable Brotli Copies with Fleet

CVE-2026-111497 is a buffer overflow in Google’s Brotli decoder (1.0.3 to 1.2.0) that is compiled into Node.js, Bun, Envoy, Python Brotli wheels, .NET and the browsers. A crafted Content-Encoding: br body reaches it with no login. The upstream fix is tiny; finding every bundled copy is the work. This post ships six Fleet queries with version logic that does not trust SQLite string comparison, a policy pattern, and what the queries found on a real fleet (hint: Pillow bundles libbrotli 1.2.0).

eMudhra CA Key Compromise: Find and Fix the Trust Stores Your Browser Doesn't Cover

Eight eMudhra intermediate CA keys were generated as tiny, guessable numbers, so anyone can forge a trusted certificate for any website. Browsers and operating systems blocked them within three days. Everything that keeps its own copy of the trusted roots did not: Linux CA bundles, macOS /etc/ssl/cert.pem, Node.js, Python certifi, and the CA bundle Fleet’s own agent uses to reach the Fleet server. This brief explains the blast radius in plain words and ships three Fleet queries and three Fleet scripts (macOS, Windows, Linux) that find and fix the exposure, tested on real hosts and containers.