Copy Fail CVE-2026-31431: Nine Years of Root Access Hidden in the Linux Kernel

Want to learn ethical hacking? I built a complete course. Have a look!
Learn penetration testing, web exploitation, network security, and the hacker mindset:
→ Master ethical hacking hands-on
Hacking is not a hobby but a way of life!
Since 2017, every major Linux distribution has been shipping a flaw that hands root access to any local user. The exploit is a 732-byte Python script that uses only what comes built into Python by default. It works on Ubuntu, Amazon Linux, RHEL, and SUSE without a single modification, leaves nothing on disk, and bypasses almost every file integrity monitoring tool in existence, because the file it corrupts is never actually written to.
Copy Fail (CVE-2026-31431) was publicly disclosed on April 29, 2026.
Most Linux privilege escalation bugs, the kind that give a regular user administrator-level control over a system, require timing tricks, repeated attempts, and a bit of luck. Dirty Cow (CVE-2016-5195) needed a race condition and sometimes crashed the system in the attempt. Dirty Pipe (CVE-2022-0847) was limited to kernel versions 5.8 and up. Copy Fail has neither of those limitations. It is a straight-line logic flaw that executes cleanly every single time, on every tested distribution, without per-system adjustments.
This does not work from the outside. An attacker needs an existing user account on the system first, which is exactly what makes the CI/CD and shared server scenarios so relevant.
Deep inside every Linux system sits a crypto interface called AF_ALG, a set of tools that any regular program, without special privileges, can use to perform encryption and decryption. It has been available for over a decade. A kernel function called splice() moves file data between processes without copying it, passing the original memory pages by reference instead. The page cache is where the kernel stores recently-accessed files in memory so it does not have to go back to disk every time. When splice() hands data over, those original page cache pages go along with it.
Researcher Taeyang Lee at Theori had been studying exactly how these pieces interact. He had a specific suspicion: that splice() could deliver page cache pages directly into the crypto subsystem in a way nobody had examined before. He fed that one observation into Xint Code, the AI security scanning tool his team built, and let it run against the entire Linux crypto subsystem.
The scan completed in about an hour. Copy Fail was the top result. The same scan also found other high-severity vulnerabilities that are still in coordinated disclosure.
Zerodium, one of the best-known zero-day brokers before going dark in 2025, listed prices up to $500,000 for high-quality Linux privilege escalation bugs. Crowdfense, which still operates, goes up to $7 million, with the top of that range reserved for exactly this kind of bug: universal, reliable, no per-distribution adjustments required. This had been sitting in the kernel since 2017.
Three completely separate changes to the Linux kernel, each innocent on its own, combined over nine years to create it.
In 2011, a component called authencesn was added to the kernel to support IPsec, the set of protocols used to secure network connections at the routing level. As part of its decryption process, authencesn shuffles a few bytes around for its own internal bookkeeping and writes four bytes just outside its designated output area while doing so. Completely harmless when it was added. The only thing calling it was the kernel itself, on memory it fully controlled.
Four years later, in 2015, the crypto interface was expanded so that regular programs could hand data directly to the kernel’s encryption routines over a socket connection. Still not a problem, because data coming in and output going back were kept in completely separate memory regions.
Then in 2017, an optimization was added to reduce unnecessary memory copying. The change allowed input and output to share the same chain of memory. It tried to be careful: the actual content was copied across to the output buffer, but the verification data at the end of the input was linked in by reference rather than copied. That linked portion was still pointing directly to the original in-memory pages of whatever file had been handed in through splice(). Page cache pages that nobody expected to be sitting in a writable part of the chain.
Nobody looked at the intersection of all three. The crypto code was reviewed many times, always through a cryptographic lens: timing side channels, validation failures, key handling. The question of whether memory in the writable output chain could belong to someone else never came up.
Because of that 2017 change, authencesn’s four-byte bookkeeping write now landed directly in the page cache of the target file. The attacker controls which file gets targeted, which position within it, and what value gets written, because all three come from the parameters of the socket call.
The kernel never marks that page as dirty. The file on disk stays completely untouched.
But the page cache is what the kernel actually reads when it loads a program to run, so the corrupted in-memory version is immediately active across the entire system. An attacker with a regular user account uses this to target a setuid binary, a program that runs with elevated privileges regardless of who launches it. The classic target is /usr/bin/su, the standard tool for switching users on Linux. Inject shellcode into its cached version, execute it, and because the binary is setuid-root, the shellcode runs as root.
This is what that looks like:
| |
The decryption call returns an error because the ciphertext is fabricated, but the four-byte write already happened and is not rolled back. The script repeats this for each chunk of the payload, then executes the binary. The same script, unmodified, achieved root on Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL, and SUSE 16 in Theori’s testing.
What makes this so hard to detect is that the write goes through the kernel’s own crypto path, not through the file system. File integrity tools like Tripwire and AIDE compare checksums of files on disk, but nothing there changed. Inotify watches for file system events, and this write had none. From the perspective of every standard monitoring tool, nothing happened.
Now for the part that makes this worse in modern infrastructure.
A container, think Docker or a Kubernetes pod, is not a separate machine. It shares the same kernel as the host and everything else running on that host. The page cache is part of the kernel, which means a process inside a container can corrupt page cache pages that belong to the host and to every other container running alongside it. Copy Fail is not just a local privilege escalation. It breaks through the container boundary entirely. Theori has a second part of this research covering the full Kubernetes node compromise in preparation, not yet published.
The environments that need to act first are multi-user servers where multiple people share login access, self-hosted CI/CD runners where pull requests trigger builds on a shared kernel, and any setup running untrusted code in containers without hardware-level isolation underneath. If a pull request can trigger a build on a self-hosted GitHub Actions or GitLab runner, that pull request can become root on the runner.
Cloud functions on microVM infrastructure like AWS Lambda and Fargate are not affected, because each tenant gets a completely separate kernel. Cloudflare Workers run on V8 isolates with no Linux kernel in the picture. gVisor interposes its own user-space kernel that does not share the host’s vulnerable code. The pattern is consistent: what holds is anything that does not share a kernel.
What to check and do right now:
- → Check your kernel version:
| |
- → Check whether anything on your system is currently using the vulnerable interface:
| |
- → Patch immediately:
| |
- → If patching right now is not possible, block the vulnerable kernel module:
| |
Blocking this module does not affect dm-crypt, LUKS disk encryption, SSH, or OpenSSL in any default configuration. It only affects software explicitly configured to use AF_ALG as its crypto backend, which is uncommon outside specialized setups.
→ For containers, block AF_ALG socket creation via seccomp policy regardless of patch status.
→ Auditd rule to flag AF_ALG socket creation:
| |
- → After patching, verify the fix is in place (requires Python 3.10+):
| |
- → SHA256 of the PoC:
a567d09b15f6e4440e70c9f2aa8edec8ed59f53301952df05c719aa3911687f9
Theori reported to the Linux kernel security team on March 23, 2026. The patch was committed to mainline on April 1. The CVE was assigned on April 22 with a CVSS score of 7.8, which reflects the local access requirement rather than the real-world impact on shared servers and containers. The full public disclosure went out on April 29.
The fix removed the 2017 optimization entirely and separated input and output back into distinct memory regions, so page cache pages can no longer end up in the writable side. The commit note says it directly: there was no benefit to doing this in-place, because input and output always came from different memory mappings anyway. The optimization solved a problem that did not exist and created this one for nine years.
The crypto subsystem had been audited many times. Always for cryptographic correctness, never for memory ownership. Nobody was asking whether the memory in the output chain could belong to someone else, because in every previous design, it could not. Three individually reasonable decisions, spread across nine years, and the bug only existed at their intersection.
An AI scanning tool found it in one hour with one observation as a starting point. It had been sitting in the mainline kernel the whole time, on every distribution, available to any local user who knew where to look.
What else is waiting in similar subsystems right now is genuinely unknown. Probably more than anyone wants to think about.
Linux privilege escalation, post-exploitation, staying persistent on a system without getting caught, and pivoting through a network after the initial breach are all covered step by step in my ethical hacking course:
Hacking is not a hobby but a way of life. 🎯
Sources: Theori / Xint Code · copy.fail · oss-security
→ Stay updated!
Get the latest posts in your inbox every week. Ethical hacking, security news, tutorials, and everything that catches my attention. If that sounds useful, drop your email below.