CVE-2026-31431: The Nine-Year Kernel Bug Hiding in Plain Sight
CVE-2026-31431: Nine Years in the Dark - Linux Kernel Copy Fail, Page Cache Corruption, and Local Privilege Escalation
A 2017 Linux kernel performance optimization silently introduced a local privilege escalation primitive that went undetected for nine years. A 732-byte Python script using only the standard library hands an attacker a root shell on Ubuntu, RHEL, Amazon Linux, SUSE, and every other mainstream Linux distribution - no compilation, no race condition, no per-distro tuning, no retry loops. The exploit was published simultaneously with disclosure on April 29, 2026. CISA confirmed active exploitation two days later.
Vulnerability at a Glance
| Field | Detail |
|---|---|
| CVE ID | CVE-2026-31431 |
| Vulnerability Name | Copy Fail |
| Affected Component | algif_aead module, AF_ALG kernel socket interface - authencesn AEAD cipher |
| Root Cause Commit | 72548b093ee3 (2017) - in-place AEAD optimization that collapsed src and dst scatterlists |
| Upstream Kernel Fix | Commit a664bf3d603d - reverts the 2017 in-place optimization |
| Vulnerability Class | Improper memory isolation during AEAD crypto operations via AF_ALG sockets (page cache corruption) |
| Discovered By | Theori and Xint |
| Disclosure Date | April 29, 2026 - simultaneous exploit release at copy.fail |
| CISA KEV Added | May 1, 2026 (BOD 22-01 patch deadline: May 15, 2026) |
| Affected Distributions | Ubuntu, RHEL, AlmaLinux, Amazon Linux 2023, Debian, Fedora, Arch Linux, SUSE, CloudLinux, and any distro shipping a kernel built from the 2017 commit onward |
| WSL2 | Affected - WSL2 runs a real Linux kernel; patched via May 2026 Windows Patch Tuesday |
| Siemens SIMATIC S7-1500 | Confirmed affected - see SSA-265688 and SSA-082556 |
Background: What Is the AF_ALG Socket Interface
To understand Copy Fail, it helps to understand why the AF_ALG socket interface exists and what role it plays in the kernel. Linux exposes hardware-accelerated cryptographic operations to userspace through a standard socket family called AF_ALG (address family 38). Instead of requiring applications to perform encryption entirely in userspace, AF_ALG allows a process to hand data to the kernel and receive the cryptographic result back - taking advantage of CPU or hardware crypto acceleration where available.
The interface operates through a two-step setup. First, a process calls socket(AF_ALG, SOCK_SEQPACKET, 0) and binds it to a named algorithm, providing parameters like the cipher suite, key material, and IV. It then calls accept() to receive an operation file descriptor. Subsequent sendmsg() and recvmsg() calls on that operation descriptor trigger the actual cryptographic work.
A critical capability of this interface is support for splice operations. The splice() system call can transfer data between two file descriptors without copying it through userspace. Critically, one of those file descriptors can be a regular file - and when it is, the data being transferred comes directly from kernel page cache, the kernel's shared in-memory buffer for file-backed data. This zero-copy pathway is where Copy Fail creates its opportunity.
The 2017 Commit That Started It All
In 2017, a performance optimization was merged into the Linux kernel for the algif_aead module (commit 72548b093ee3). The change was straightforward in intent: during AEAD (Authenticated Encryption with Associated Data) operations, instead of maintaining separate source and destination scatterlists, the optimization collapsed them into a single combined scatterlist that both req->src and req->dst pointed to simultaneously.
This meant the AEAD implementation would process data in place - reading from and writing to the same memory region. For most AEAD algorithm implementations, this causes no problem. The read completes before any write begins, and the fact that src and dst share the same backing memory is inconsequential.
The authencesn algorithm is different. During its AEAD operation, authencesn uses the destination buffer as a scratch pad before it has finished consuming the source input. When req->src and req->dst both point to the same scatterlist, this scratch write contaminates the data mid-operation. The algorithm writes into the destination region while that same memory is still being read as input. The result is a 4-byte write at an attacker-influenced offset into whatever memory backs the destination scatterlist.
/usr/bin/su) into the AF_ALG operation via splice(), those 4 bytes land inside the kernel's in-memory representation of that executable. The on-disk binary is never touched. The modification lives entirely in page cache - and because page cache is shared kernel-wide, every subsequent execution of that binary on the system runs the corrupted in-memory version until the page is evicted.
Step-by-Step: How the Exploit Path Works
# Step 1: Open an AF_ALG socket - no capabilities required socket(AF_ALG=38, SOCK_SEQPACKET=5, 0) # Step 2: Bind to the vulnerable AEAD algorithm bind(fd, {alg_type='aead', alg_name='authencesn(hmac(sha256),cbc(aes))'}) # Step 3: Accept an operation file descriptor op_fd = accept(fd) # Step 4: Open the target setuid binary - page cache gets populated suid_fd = open("/usr/bin/su", O_RDONLY) # Step 5: Splice page cache pages into the AEAD op fd (zero-copy) splice(suid_fd, NULL, op_fd, NULL, PAGE_SIZE, 0) └── page cache pages of /usr/bin/su now in the writable dst scatterlist # Step 6: Trigger the AEAD operation sendmsg / recvmsg └── authencesn uses dst as scratch pad └── 4-byte write lands in page cache of /usr/bin/su └── in-memory binary is now corrupted - disk file unchanged # Step 7: Repeat ~40 iterations across different page offsets └── delivers sufficient corruption to redirect setuid execution # Step 8: Execute the corrupted setuid binary exec("/usr/bin/su") └── root shell spawned
Why File Integrity Monitoring Cannot See This
One of the most operationally significant properties of Copy Fail is its relationship with file integrity monitoring. Tools like Tripwire, AIDE, and similar FIM solutions work by recording cryptographic hashes of files on disk and alerting when those hashes change. They compare what is stored on disk against a known-good baseline.
Copy Fail never touches the disk. The authencesn scratch write lands in page cache - the kernel's in-memory read buffer for file-backed data. The on-disk bytes of /usr/bin/su remain exactly as they were before exploitation. An sha256sum of the file produces the correct, expected hash. AIDE reports no changes. Tripwire reports no changes. Any audit mechanism that compares inode metadata, file size, timestamps, or disk-level checksums sees nothing.
The modification exists only in the kernel's page cache, a shared in-memory structure with no direct on-disk counterpart. It persists until memory pressure forces eviction or the system reboots. During that window, every process on the system that executes the targeted setuid binary invokes the corrupted in-memory version.
| Detection Mechanism | Effective Against Copy Fail | Reason |
|---|---|---|
| Tripwire / AIDE (disk hash) | No | Hashes on-disk bytes only - page cache modification is invisible |
| inotify / fanotify (file events) | No | splice-driven page cache writes do not raise inode change events |
| SELinux / AppArmor policy | Partial | Can restrict AF_ALG socket creation - does not detect if already permitted by policy |
| auditd syscall monitoring | Yes | AF_ALG socket (family 38) creation by non-root is a high-confidence indicator |
| eBPF / bpftrace runtime | Yes | Tracepoint on sys_enter_socket with family=38 and uid!=0 catches it live |
| Page cache integrity check | Yes | Comparing in-memory page cache hashes against on-disk checksums reveals the modification |
| EDR behavioral analysis | Yes | Unprivileged process acquiring UID 0 without going through sudo or PAM is strongly anomalous |
Affected Distributions and Scope
Copy Fail affects any Linux kernel built after commit 72548b093ee3 landed in mainline in 2017 and before the April 2026 vendor patches were applied. That window covers essentially every mainstream Linux distribution that shipped kernel packages between 2017 and April 29, 2026.
| Distribution | Patch Status | Notes |
|---|---|---|
| Ubuntu | Patched | Interim kmod blacklist released April 30; full kernel image packages followed in early May 2026 |
| AlmaLinux | Patched | Patched April 30, 2026 - ahead of upstream RHEL |
| RHEL / CentOS Stream | Patched | Patches available; check Red Hat security bulletin for exact build numbers |
| Amazon Linux 2023 | Patched | AWS kernel updates released; verify via yum update kernel and reboot |
| Debian | Patched | Upstream fix available via standard security update channel |
| Fedora | Patched | Rapid release cadence; patched quickly post-disclosure |
| Arch Linux | Patched | Rolling release - update via pacman -Syu |
| SUSE / openSUSE | Patched | Patches available via SUSE security channels |
| CloudLinux | Patched | Patched kernels and KernelCare livepatches available May 1-2, 2026 |
| Windows WSL2 | Patched | WSL2 runs a real Linux kernel; updated via May 2026 Windows Patch Tuesday |
| Siemens SIMATIC S7-1500 | Advisory Issued | SSA-265688 and SSA-082556 - see Siemens CERT portal for per-product remediation |
algif_aead kernel module can be blacklisted without affecting dm-crypt, LUKS, kTLS, IPsec, SSH, or standard OpenSSL and GnuTLS builds. Only applications explicitly using AF_ALG for AEAD ciphers are impacted - an uncommon production configuration. Full patching and mitigation steps are in Part 4 of this series.
How Copy Fail Compares to Previous Linux LPEs
Linux local privilege escalation vulnerabilities are not unusual, but Copy Fail's operational characteristics separate it from its predecessors. The two most comparable high-profile Linux LPEs are Dirty Cow (CVE-2016-5195) and Dirty Pipe (CVE-2022-0847), both of which involved manipulation of page cache or copy-on-write mechanisms. The comparison matters because it clarifies exactly what makes Copy Fail a different class of threat.
SafeBreach researchers confirmed that the same unmodified 732-byte script produced root shells across Ubuntu, RHEL, Amazon Linux, SUSE, and Arch Linux. No recompilation, no kernel version detection, no per-distro offset tables. This cross-distro reliability means an attacker with local access to any Linux host can immediately attempt privilege escalation without knowing the distribution, kernel version, or installed toolset in advance - a qualitative shift from what previous LPEs required.
