CopyFail, Dirty Frag, and Fragnesia: The Linux Kernel Page Cache LPE Trilogy
Technical breakdown of CopyFail, Dirty Frag, and Fragnesia: how three page-cache memory flaws enabled unprivileged local root escalation in the Linux kernel.
In the span of two weeks, three Linux kernel local privilege escalation vulnerabilities dropped in rapid succession — each one building on the last, each one trivially exploitable from an unprivileged user account, and each one affecting essentially every major Linux distribution running a kernel from 2017 onward. CopyFail, Dirty Frag, and Fragnesia all exploit the same underlying attack surface: the kernel's page cache. If you run shared Linux hosts, containers, CI runners, or Kubernetes nodes and have not patched, stop reading and go do that first.
The Common Thread: Page Cache Corruption
The page cache is the kernel's in-memory store of file contents. When a program reads a file, the kernel loads it into the page cache and hands out references to that cached copy. When a setuid binary like /usr/bin/su executes, the kernel maps those cached pages and runs them with elevated privileges. The security model depends on a critical assumption: the page cache accurately reflects the file's contents on disk.
If an unprivileged user can corrupt page cache entries for a file they cannot normally write to — a setuid root binary — they can cause the kernel to execute attacker-controlled code when that binary runs, with that binary's elevated privileges. This is the same class of attack as Dirty Pipe (CVE-2022-0847) from 2022. The attack vector in all three cases is zero-copy syscalls: splice(), sendfile(), vmsplice() — interfaces that move data between file descriptors and pipes without copying through userspace. The bugs are all failures of ownership validation in different kernel subsystems, allowing controlled writes into pages the attacker should not own.
CopyFail — CVE-2026-31431
Overview
Disclosed: April 29, 2026. Discoverer: Xint Code. CVSS: 7.8 HIGH. Vulnerable since: Linux 4.14 (2017). Affected module: algif_aead (AF_ALG kernel Crypto API, AEAD hardware acceleration).
The Bug
CopyFail abuses the AF_ALG socket interface — the kernel's Crypto API socket family for hardware-accelerated cryptographic operations. When a user sends data to an AF_ALG AEAD socket via splice(), the kernel attaches pages from the user's pipe to the socket's internal scatter-gather list. The kernel calls get_page() to take a reference to these pages but does not verify that the pages being attached are actually owned by the caller.
This means a user can splice pages from a read-only page cache entry backing /usr/bin/su into the AF_ALG socket. The AEAD processing pipeline then writes the operation's output back into those same pages, corrupting them. The result is a controlled 4-byte write primitive into arbitrary page cache entries. With repeated writes, an attacker overwrites the entry point of a setuid binary in memory without touching the file on disk. Integrity monitoring tools see nothing because the filesystem is unmodified.
$ ./copyfail
[*] CVE-2026-31431 PoC (Copy Fail)
[*] /usr/bin/su entry @ file offset 0x78
[*] Patching page cache (40 bytes, 10 writes) ..........
[+] Executing /usr/bin/su
# id
uid=0(root) gid=1000(user) groups=1000(user)The public PoC is 732 bytes of C. It runs in seconds on every major distribution. Ubuntu 22.04, 24.04, Debian 12, RHEL 8/9, Fedora, Arch, Alpine — all vulnerable.
Mitigation
# Unload the vulnerable module immediately
sudo modprobe -r algif_aead
# Blacklist to prevent auto-loading across reboots
echo 'blacklist algif_aead' | sudo tee /etc/modprobe.d/copyfail.conf
sudo update-initramfs -u # Debian/Ubuntu
# sudo dracut --force # RHEL/Fedora
# If compromise is possible, drop page cache first
sudo sh -c 'sync && echo 3 > /proc/sys/vm/drop_caches'Dirty Frag — CVE-2026-43284 and CVE-2026-43500
Overview
Disclosed: May 8, 2026. Discoverer: Hyunwoo Kim (@v4bel). Also known as CopyFail2 — reverse-engineered partly from the CopyFail fix commit. CVEs: CVE-2026-43284 (xfrm-ESP / IPsec) and CVE-2026-43500 (RxRPC). Affected modules: esp4, esp6, rxrpc.
Two Bugs, Two Paths
Dirty Frag is a vulnerability chain combining two independent page-cache write primitives in different networking subsystems.
CVE-2026-43284 lives in the xfrm-ESP subsystem — the kernel's IPsec ESP implementation. When the ESP layer processes outbound packets, it uses skb_page_frag_refill() to allocate page fragments for the payload. Under specific conditions, the kernel attaches these fragments to pages it does not exclusively own. The subsequent in-place encryption writes into those borrowed pages — which can be page-cache entries backing a target file.
CVE-2026-43500 lives in RxRPC — the kernel's Andrew File System RxRPC protocol implementation. The receive path has an analogous flaw where received packet data is written into page fragments that can be page-cache-backed. The critical difference: the RxRPC path does not require an unprivileged user namespace, bypassing AppArmor's unprivileged_userns restrictions present on Ubuntu 24.04. On kernels where the ESP path is blocked by AppArmor policy, an attacker can pivot to RxRPC.
Which Path on Which Kernel
Ubuntu 22.04 (kernel 5.15): ESP path exploitable. RxRPC path not applicable (introduced in kernel 6.4). Ubuntu 24.04 (kernel 6.8): ESP path blocked by AppArmor apparmor_restrict_unprivileged_userns=1. RxRPC path bypasses this and is exploitable. Other distributions: depends on AppArmor/SELinux policy and kernel version.
# Check which path applies to your system
uname -r
sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null
lsmod | grep -E 'esp4|esp6|rxrpc'
# Mitigation: blacklist all three modules
cat << 'EOF' | sudo tee /etc/modprobe.d/dirtyfrag.conf
blacklist esp4
blacklist esp6
blacklist rxrpc
EOF
# Unload if not in active use
sudo modprobe -r rxrpc 2>/dev/null
# Note: do not unload esp4/esp6 if IPsec VPN is active
sudo update-initramfs -u && sudo rebootContainer and Kubernetes Impact
The page cache is shared across the host and all containers. A pod running as UID 1000 can escalate to root on the Kubernetes node. AppArmor policies restricting user namespaces at the pod level do not prevent exploitation via the RxRPC path. Every node needs the blacklist applied at the host level, not inside containers.
Fragnesia — CVE-2026-46300
Overview
Disclosed: May 13, 2026. Discoverer: William Bowling (Zellic.io / V12 Security), using AI-assisted code auditing. Affected module: xfrm-ESP (same as CVE-2026-43284). No upstream kernel patch at time of disclosure — embargo broken before fix was ready.
The Patch That Created a New Vulnerability
Fragnesia is the most uncomfortable entry in this family. The Dirty Frag fix for CVE-2026-43284 changed how the ESP subsystem handles page fragment coalescing — specifically, how skb_try_coalesce() combines scattered page fragments in a socket buffer into contiguous memory. The change that fixed CVE-2026-43284 altered fragment attachment logic in a way that created a new window where paged fragments from one sk_buff are attached into another without proper page ownership validation.
The result: another page-cache write primitive through the same xfrm-ESP code path, via a different code flow the original fix did not address. Hyunwoo Kim, who discovered Dirty Frag, confirmed that Fragnesia was accidentally activated by the CVE-2026-43284 patch. Bowling found it by analyzing the fix commit with Zellic's AI auditing tool — the model recognized that the patch changed page ownership semantics in a way that introduced a new primitive.
The public PoC overwrites /usr/bin/su through the page cache and yields a root shell. Because Fragnesia lives in the same ESP/XFRM subsystem, the same blacklist that mitigates Dirty Frag also mitigates Fragnesia — blacklisting esp4 and esp6 stops both.
The Patch Race
Fragnesia was disclosed simultaneously on GitHub and X at the moment the fix appeared on the netdev mailing list — no embargo. A working public exploit existed with no upstream kernel patch available. Distributions had to ship their own patches while the fix worked through review. This is the new norm: defenders and exploit developers are operating on the same timeline.
The Structural Problem: Zero-Copy Complexity
All three vulnerabilities share a structural root cause. Zero-copy I/O was designed for performance — moving data without copying through userspace is important for high-throughput workloads. But zero-copy means the kernel allows external references to its internal memory management structures, specifically the page cache. Every place where zero-copy interfaces touch the networking or crypto stack is a potential site for the confusion between exclusively-owned pages and page-cache-backed pages that all three exploits rely on.
CopyFail found one such site in AF_ALG. Dirty Frag found two more in ESP and RxRPC. Fragnesia found that the fix for one of them introduced a third. The pattern is consistent enough that AI-assisted auditing tools can now recognize it in unfixed code — meaning both defenders and attackers can find the next instance faster than before.
Full Remediation Guide
1. Patch First
# Debian/Ubuntu
sudo apt update && sudo apt upgrade linux-image-generic && sudo reboot
# RHEL / AlmaLinux / Rocky
sudo dnf update kernel && sudo reboot
# Arch Linux
sudo pacman -Syu linux && sudo reboot2. Module Blacklisting (if patching is not yet possible)
# Block all vulnerable modules across all three CVEs
cat << 'EOF' | sudo tee /etc/modprobe.d/page-cache-lpe.conf
blacklist algif_aead
blacklist esp4
blacklist esp6
blacklist rxrpc
EOF
# Unload where possible
sudo modprobe -r algif_aead rxrpc 2>/dev/null
# Only unload esp4/esp6 if IPsec is not in active use
# Rebuild initramfs
sudo update-initramfs -u # Debian/Ubuntu
sudo dracut --force # RHEL/Fedora
sudo reboot3. Drop the Page Cache on Potentially Compromised Systems
# Force reload of all file data from disk
sudo sh -c 'sync && echo 3 > /proc/sys/vm/drop_caches'
# Verify critical binaries against package manager
# Debian/Ubuntu:
dpkg --verify
# RHEL/AlmaLinux:
rpm -Va4. Detection
# Monitor for AF_ALG socket creation (CopyFail indicator)
sudo auditctl -a always,exit -F arch=b64 -S socket -F a0=38 -k af_alg
# Monitor for splice() on suspicious fds
sudo auditctl -a always,exit -F arch=b64 -S splice -k splice_watch
# Check logs
sudo ausearch -k af_alg -ts today
sudo ausearch -k splice_watch -ts today5. Kubernetes and Container Clusters
Apply module blacklisting and kernel patches at the node level across every node in every cluster. The page cache is host-wide — container-level mitigations do not protect the host or other containers. Managed services (AKS, EKS, GKE) have all mitigated these CVEs at the node level, but verify your node image versions.
Risk Assessment by Environment
Lowest risk: single-user workstations and single-tenant servers where only the owner has shell access. These require local code execution to exploit. Highest risk: shared Linux hosts with multiple untrusted users, container clusters and Kubernetes nodes, CI/CD runners and build farms where untrusted code runs (this includes GitHub Actions self-hosted runners), cloud SaaS infrastructure on shared multi-tenant hosts, and any host where an attacker has already established low-privilege access via another vector — web shell, phishing, supply chain compromise, or container escape.
The supply chain attack landscape we have been covering — TeamPCP, TanStack, the Bitwarden CLI compromise — represents exactly this threat model. An attacker who gains a foothold as an unprivileged process in a CI pipeline or container now has a trivially reliable path to root on any unpatched node. These three vulnerabilities are not theoretical risks for those environments. Treat them accordingly.
References
CopyFail: copy.fail | CVE-2026-31431 NVD | Ubuntu advisory | Microsoft MSRC. Dirty Frag: Wiz Research analysis | Microsoft Security blog | v4bel GitHub PoC | Azure AKS issue #5753. Fragnesia: TuxCare analysis | Help Net Security | Zellic disclosure | Wiz follow-up. For Kubernetes operators: the Azure AKS issue thread has the most detailed per-kernel-version breakdown of which exploit path applies to which distribution.