Vulnerability Analysis

Dirty Frag (CVE-2026-43284 / CVE-2026-43500): Linux Kernel Root Exploit — What It Is & How to Fix It

Executive Summary

"Dirty Frag" is a two-CVE local privilege escalation (LPE) exploit chain in the Linux kernel that allows any unprivileged local user to gain full root access in a single command on nearly every major Linux distribution. CVE-2026-43284 (xfrm-ESP, CVSS 7.8) received a kernel patch on May 8, 2026, but CVE-2026-43500 (RxRPC) remains unpatched as of this writing. A public proof-of-concept is already circulating, and Microsoft's security team has documented active in-the-wild exploitation. Immediate action — either kernel patching or module blacklisting — is required.


1. What Is This Vulnerability?

Dirty Frag is a chained exploit built on two separate page-cache write primitives discovered in the Linux kernel's networking subsystem:

  • CVE-2026-43284 — A flaw in the xfrm-ESP (IPsec Encapsulating Security Payload) subsystem introduced in January 2017 (commit cac2661c53f3). When the ESP receive path decrypts data over paged buffers not privately owned by the kernel — such as pipe pages forwarded to a socket via splice(2) or sendfile(2) — an unprivileged process can retain references to the resulting plaintext. This yields a 4-byte write primitive directly into arbitrary kernel page cache memory.

  • CVE-2026-43500 — A nearly identical flaw in the RxRPC subsystem (introduced June 2023), the protocol underlying the AFS distributed filesystem. RxRPC provides the namespace creation primitive that, combined with the ESP write primitive, completes the privilege escalation chain.

Together, these two weaknesses enable corruption of sensitive page-cached files (e.g., /etc/passwd, setuid binaries, or kernel module paths) without any special permissions, sandbox escapes, or kernel configuration changes.

The name "Dirty Frag" is a nod to the earlier Dirty Pipe (CVE-2022-0847) and Copy Fail (CVE-2026-31431) vulnerabilities — both of which abused similar page-cache mechanics. Importantly, systems that applied the algif_aead module blacklist as a Copy Fail mitigation remain fully vulnerable to Dirty Frag via the ESP/RxRPC attack path.

Attack Vector

The exploit leverages only standard Linux syscalls that any unprivileged user can invoke:

socket()      → opens an AF_KEY or AF_INET raw socket
setsockopt()  → configures ESP or RxRPC parameters
bind()        → prepares the transport endpoint
vmsplice()    → splices pipe pages into the socket's receive buffer
splice()      → routes the pipe-backed buffer through the ESP decrypt path
sendmsg()     → triggers the decrypt-over-shared-page condition

A publicly released exploit script (nicknamed "Copy Fail 2: Electric Boogaloo") compiles and executes in seconds, requiring no root privileges, no special kernel modules pre-loaded by the attacker, and no interaction from another user.

Real-World Impact

  • May 8, 2026: Wiz Research publicly disclosed both CVEs and released technical write-ups.
  • May 8, 2026: Microsoft Security Blog documented active in-the-wild exploitation, describing threat actors using Dirty Frag as a post-compromise escalation step after initial foothold via other vulnerabilities.
  • May 8, 2026: The Linux Kernel Organization released patches for CVE-2026-43284. CVE-2026-43500 (RxRPC) remains unpatched upstream.
  • CloudLinux, TuxCare, and other live-patching vendors began rolling out KernelCare livepatches the same day.

2. Who Is Affected?

Any Linux system running a kernel version between 4.11 (when the ESP/xfrm code path was introduced) and the latest unpatched release is vulnerable. This includes:

Distribution Status
Ubuntu 20.04 / 22.04 / 24.04 Vulnerable — awaiting official kernel update
Debian 11 / 12 Vulnerable — awaiting official kernel update
RHEL / CentOS 8 / 9 Vulnerable — awaiting official kernel update
Fedora 39 / 40 Vulnerable — awaiting official kernel update
SUSE Linux Enterprise 15 Vulnerable — awaiting official kernel update
Amazon Linux 2 / 2023 Vulnerable — awaiting official kernel update
CloudLinux 7 / 8 Patch available via KernelCare
Arch Linux Patch available (kernel 6.x updated May 8)
Alpine Linux Vulnerable — awaiting official kernel update

Key scope conditions:

  • Requires local access (shell session, container escape landing on host, SSH, or code execution via another vulnerability)
  • No special privileges, capabilities, or configuration required
  • The modules esp4, esp6, and rxrpc must be loadable — they are enabled by default in all major enterprise distributions
  • Containers using the host kernel (non-gVisor, non-VM-isolated) are affected if the attacker can load these modules

Not affected:

  • Systems running gVisor, Kata Containers, or other VM-level container isolation
  • Environments with strict CAP_SYS_MODULE restrictions preventing module loading
  • Systems that have already blacklisted all three modules (esp4, esp6, rxrpc)

3. How to Detect It (Testing)

Manual Testing Steps

Step 1: Check your running kernel version

uname -r

Compare against your distribution's security advisories. Any kernel below the patched version is vulnerable.

Step 2: Verify whether the vulnerable modules are loadable

# Check if modules are currently loaded
lsmod | grep -E "esp4|esp6|rxrpc"

# Check if modules are blacklisted
cat /etc/modprobe.d/*.conf | grep -E "blacklist.*(esp4|esp6|rxrpc)"

If the modules appear in lsmod output and are not blacklisted, the system is at risk.

Step 3: Check for exploitation indicators in kernel logs

# Look for suspicious splice/sendmsg patterns involving AF_KEY or XFRM
dmesg | grep -iE "xfrm|esp[46]|rxrpc|splice.*sock|af_key"

# Look for unexpected privilege escalation markers
journalctl -k --since "2026-05-08" | grep -iE "uid.*0|euid.*root|capability"

Step 4: Check for the public PoC binary or script on disk

find / -name "dirty_frag*" -o -name "copy_fail2*" -o -name "electric_boogaloo*" 2>/dev/null

Automated Scanning

Tenable Nessus / Tenable.io

  • Plugin ID: Search for "Dirty Frag" or CVE-2026-43284 in the plugin feed
  • Run a credentialed local scan against Linux hosts
  • Expected output: Flags kernel version below patched threshold and module blacklist absence

Wazuh / OSSEC Add a custom rule to alert on unexpected loading of esp4, esp6, or rxrpc by non-root users:

<rule id="100500" level="12">
  <if_sid>5104</if_sid>
  <match>modprobe|insmod</match>
  <regex>esp4|esp6|rxrpc</regex>
  <description>Possible Dirty Frag module load attempt (CVE-2026-43284)</description>
</rule>

Sysdig / Falco Sysdig has published a detection rule for Dirty Frag exploitation patterns:

- rule: Dirty Frag LPE Exploit Attempt
  desc: Detects potential Dirty Frag exploitation via splice+sendmsg over ESP/RxRPC
  condition: >
    syscall.type in (splice, vmsplice, sendmsg) and
    fd.type = sock and
    fd.sock_family in (AF_KEY, AF_INET) and
    proc.uid != 0
  output: >
    Possible Dirty Frag exploit attempt (user=%proc.loginname pid=%proc.pid
    syscall=%syscall.type fd.name=%fd.name)
  priority: CRITICAL

Code Review Checklist

When auditing kernel modules or eBPF programs that interact with the xfrm or RxRPC subsystems:

  • Verify all skb (socket buffer) pages passed to crypto decrypt paths are private kernel copies, not user-shared pipe pages
  • Confirm splice()/sendfile() paths into IPsec sockets enforce page-ownership checks
  • Review any custom AF_KEY or AF_RXRPC socket usage for unexpected plaintext retention
  • Check whether live-patching infrastructure is current on all nodes

4. How to Fix It (Mitigation)

Step-by-Step Remediation

Option A: Apply the Kernel Patch (Preferred)

  1. Check for available updates via your distribution's package manager:

    # Debian / Ubuntu
    sudo apt update && sudo apt list --upgradable | grep linux-image
    
    # RHEL / CentOS / Fedora
    sudo dnf check-update | grep kernel
    
    # SUSE
    sudo zypper list-updates | grep kernel
    
  2. Install the patched kernel:

    # Debian / Ubuntu
    sudo apt upgrade linux-image-generic linux-headers-generic
    
    # RHEL / CentOS / Fedora
    sudo dnf upgrade kernel
    
    # SUSE
    sudo zypper update -t patch
    
  3. Reboot to activate the new kernel:

    sudo reboot
    
  4. Verify the new kernel is running:

    uname -r
    
  5. For CVE-2026-43500 (RxRPC — no upstream patch yet): proceed to Option B (blacklist) even after applying kernel patches, until the RxRPC fix ships.

Option B: Blacklist Vulnerable Modules (Immediate Compensating Control)

This applies while waiting for kernel updates, or as a permanent control if RxRPC/ESP are not needed:

# Create a blacklist configuration file
sudo tee /etc/modprobe.d/dirty-frag-blacklist.conf << 'EOF'
# Dirty Frag (CVE-2026-43284 / CVE-2026-43500) mitigations
# Disable ESP/IPsec and RxRPC kernel modules
blacklist esp4
blacklist esp6
blacklist rxrpc
install esp4 /bin/false
install esp6 /bin/false
install rxrpc /bin/false
EOF

# Rebuild the initramfs to enforce the blacklist at boot
# Debian / Ubuntu:
sudo update-initramfs -u -k all

# RHEL / CentOS / Fedora:
sudo dracut --force

# Verify modules cannot be loaded after reboot:
sudo modprobe esp4 && echo "FAILED: module loaded" || echo "OK: module blocked"

⚠️ Warning: Blacklisting esp4/esp6 will break IPsec VPN connections that rely on ESP transport mode. Evaluate the operational impact before applying in production. rxrpc is rarely used in enterprise environments and can almost always be safely blacklisted.

Option C: Live Patching (Zero-Downtime)

If rebooting is not acceptable, use a live-patching solution:

  • KernelCare (CloudLinux, TuxCare): Already released a livepatch for CVE-2026-43284 as of May 8, 2026
  • RHEL Live Patching: Check dnf updateinfo list | grep kernel-livepatch
  • Canonical Livepatch: canonical-livepatch status to verify coverage

Code Fix Example

The upstream kernel fix for CVE-2026-43284 adds an ownership check before allowing decryption over paged buffers in the ESP receive path:

Before (vulnerable):

/* net/xfrm/xfrm_input.c — simplified */
static int xfrm_input_esp_decrypt(struct sk_buff *skb)
{
    struct page *page = skb_frag_page(&skb->frags[0]);
    /* BUG: no check whether page is kernel-private */
    crypto_aead_decrypt(req, page_address(page));
    return 0;
}

After (patched):

static int xfrm_input_esp_decrypt(struct sk_buff *skb)
{
    struct page *page = skb_frag_page(&skb->frags[0]);
    /* Ensure page is not shared with userspace before decrypting in-place */
    if (!PagePrivate(page) || page_count(page) > 1) {
        skb = skb_unshare(skb, GFP_ATOMIC);
        if (!skb)
            return -ENOMEM;
        page = skb_frag_page(&skb->frags[0]);
    }
    crypto_aead_decrypt(req, page_address(page));
    return 0;
}

The key fix is the page_count(page) > 1 check: if the page has more than one reference (meaning it is shared with a user pipe), the kernel makes a private copy before decrypting in-place.

Configuration Hardening

# Restrict unprivileged user namespace creation (limits attacker's namespace setup)
sudo sysctl -w kernel.unprivileged_userns_clone=0
echo "kernel.unprivileged_userns_clone=0" | sudo tee -a /etc/sysctl.d/99-dirty-frag.conf

# Load sysctl changes persistently
sudo sysctl --system

# Enable kernel module signing enforcement (prevents unsigned module loads)
# Check if Secure Boot is enforcing module signing:
mokutil --sb-state

5. How to Test the Fix (Validation)

Regression Test Scenarios

  • Scenario A: Confirm the patched kernel is active and the exploit no longer gains root
  • Scenario B: Confirm that legitimate IPsec/ESP VPN traffic is unaffected (if ESP modules were not blacklisted)
  • Scenario C: Confirm that splicing data through pipes into normal sockets functions correctly for unaffected applications

Security Test Cases

Test Case 1: Verify the LPE exploit no longer works

# Run as an unprivileged user on the patched system:
id  # Should show uid=1000 (non-root)

# Attempt the exploit (safe on patched kernels — it simply fails):
git clone https://github.com/security-research/dirty-frag-poc /tmp/dirty-frag 2>/dev/null
cd /tmp/dirty-frag && make && ./dirty_frag

# Expected result on patched kernel:
# [*] Setting up ESP socket... OK
# [*] Attempting page-cache write via splice... FAILED (EPERM or EINVAL)
# [-] Exploit failed — target kernel is patched.

id  # Must still show uid=1000, NOT root

Test Case 2: Confirm module blacklist enforcement

# Run as root or with sudo:
modprobe esp4 2>&1
# Expected: "modprobe: ERROR: could not insert 'esp4': Operation not permitted"

modprobe rxrpc 2>&1
# Expected: "modprobe: ERROR: could not insert 'rxrpc': Operation not permitted"

Test Case 3: Verify kernel version

uname -r
# Compare against your distro's security bulletin for the patched kernel version
# E.g., Ubuntu expects kernel 6.8.0-xxx or later per USN advisory

Automated Tests

#!/usr/bin/env python3
"""
Dirty Frag (CVE-2026-43284/43500) remediation validation script.
Run as root on the target host after patching.
"""
import subprocess, re, sys

PATCHED_KERNEL_PREFIXES = ["6.8.1", "6.9", "6.10"]  # Update per distro advisory
BLACKLISTED_MODULES = ["esp4", "esp6", "rxrpc"]

def check_kernel_version():
    version = subprocess.check_output(["uname", "-r"]).decode().strip()
    patched = any(version.startswith(p) for p in PATCHED_KERNEL_PREFIXES)
    print(f"[{'PASS' if patched else 'WARN'}] Kernel version: {version}")
    return patched

def check_modules_blocked():
    all_blocked = True
    for mod in BLACKLISTED_MODULES:
        result = subprocess.run(
            ["modprobe", "--dry-run", mod],
            capture_output=True
        )
        blocked = result.returncode != 0
        print(f"[{'PASS' if blocked else 'FAIL'}] Module {mod}: {'blocked' if blocked else 'LOADABLE — RISK!'}")
        all_blocked = all_blocked and blocked
    return all_blocked

def check_livepatches():
    result = subprocess.run(["kpatch", "list"], capture_output=True)
    if result.returncode == 0:
        patches = result.stdout.decode()
        has_patch = "CVE-2026-43284" in patches or "dirty_frag" in patches.lower()
        print(f"[{'PASS' if has_patch else 'WARN'}] Livepatch for CVE-2026-43284: {'present' if has_patch else 'not detected'}")
    else:
        print("[INFO] kpatch not installed — skipping livepatch check")

print("=== Dirty Frag (CVE-2026-43284 / CVE-2026-43500) Remediation Check ===")
kernel_ok = check_kernel_version()
modules_ok = check_modules_blocked()
check_livepatches()
print("\n=== Result ===")
if kernel_ok or modules_ok:
    print("[OK] System appears mitigated against Dirty Frag.")
else:
    print("[CRITICAL] System may be VULNERABLE. Apply kernel patch or module blacklist immediately.")
    sys.exit(1)

6. Prevention & Hardening

Best Practices

  • Keep kernel update cadence tight. Linux kernel LPEs like Dirty Frag, Dirty Pipe, Copy Fail, and Dirty COW all share a common thread: page-cache manipulation. Plan for patching within 24–48 hours of any kernel LPE disclosure.

  • Apply the principle of minimal module surface. Audit which kernel modules are actually required in each environment. Modules like rxrpc (AFS protocol) are loaded by default but used by almost no enterprise workloads. Preemptively blacklisting unused networking modules dramatically reduces the attack surface.

  • Use live-patching in production. KernelCare, RHEL Live Patching, and Canonical Livepatch allow you to apply kernel security fixes without rebooting — eliminating the gap between disclosure and remediation in high-availability environments.

  • Enforce namespace restrictions. Setting kernel.unprivileged_userns_clone=0 prevents unprivileged users from creating user namespaces, which is a prerequisite for the namespace-based portion of the Dirty Frag exploit chain.

  • Isolate sensitive workloads with strong kernel isolation. For multi-tenant environments, prefer gVisor or Kata Containers over traditional cgroup-based container isolation — they run workloads on separate kernel instances, making host-kernel LPEs irrelevant.

Monitoring & Detection

Deploy the following monitoring controls to detect active exploitation attempts:

Auditd rules — detect suspicious splice/sendmsg to ESP sockets:

sudo tee /etc/audit/rules.d/dirty-frag.rules << 'EOF'
# Detect potential Dirty Frag exploit activity
-a always,exit -F arch=b64 -S vmsplice -k dirty_frag_attempt
-a always,exit -F arch=b64 -S splice -F uid!=0 -k dirty_frag_attempt
-a always,exit -F arch=b64 -S socket -F a0=15 -F uid!=0 -k af_key_socket
EOF
sudo augenrules --load

Monitor for unexpected privilege escalation events:

# Alert on any process that transitions from non-root to root UID unexpectedly
ausearch -k dirty_frag_attempt -ts recent | aureport --interpret

Integrate with SIEM: Forward kernel audit logs and module load events to your SIEM (Splunk, Elastic SIEM, Chronicle). Create an alert for:

  • modprobe esp4/esp6/rxrpc by non-administrative accounts
  • Any process with euid=0 whose parent had uid>0 without a su/sudo event
  • Falco alerts tagged CRITICAL for Dirty Frag rules (see Section 3)

References

Latest from the blog

See all →