CVE-2026-31431 (CopyFail): Reproducing a Nine-Year Kernel Bug
Author: Michael
Published: May 2026
Original Discovery: Taeyang Lee @ Theori (assisted by Xint Code AI)
CVE: CVE-2026-31431
CVSS: 7.8 (High)
Type: Local Privilege Escalation
Component: Linux kernel AF_ALG AEAD subsystem (algif_aead.c)
Patched: April 1, 2026 (mainline commit a664bf3d603d)
Why This Research Exists
When Theori published their disclosure of CopyFail on April 29, 2026, the writeup immediately stood out. A 732-byte, 10-line Python script that achieves reliable local privilege escalation on every major Linux distribution, across every architecture, with no race condition. That kind of claim demands independent verification.
This post documents my reproduction of the CopyFail primitive on a live system, my analysis of the three kernel commits that created the vulnerability, and what makes this bug structurally different from its predecessors. All credit for the original discovery belongs to Taeyang Lee and the Theori team.
The Three Commits That Broke Everything
CopyFail isn’t a single mistake. It’s the convergence of three individually reasonable kernel changes spanning six years.
The first was the addition of authencesn in 2011, an AEAD wrapper for IPsec Extended Sequence Numbers.
The second was the introduction of AF_ALG AEAD socket support in 2015, which gave userspace access to kernel cryptographic operations.
The third, and the one that created the vulnerability, was commit 72548b093ee3 in 2017.
That commit added an in-place optimization in algif_aead.c, setting req->src = req->dst to avoid allocating separate input and output buffers.
None of these were dangerous on their own. The 2017 optimization was a straightforward performance improvement. It was reviewed, merged, and forgotten for nine years.
How the Primitive Works
The attack has four stages, and the elegance is in how each one is completely ordinary on its own.
Socket setup.
An unprivileged user opens an AF_ALG socket and binds it to authencesn(hmac(sha256),cbc(aes)).
No special permissions are required.
No capabilities, no group membership.
The kernel hands this to anyone who asks.
Page cache injection via splice().
The attacker uses splice() to feed the page cache pages of a target file into the crypto socket’s input scatterlist.
Because splice() delivers zero-copy references, the socket now holds direct pointers to the kernel’s cached pages of that file.
This is the key insight Theori identified: splice() can deliver page cache references of read-only files to crypto TX scatterlists.
The in-place corruption.
Due to the 2017 optimization, the kernel sets req->src = req->dst.
During AEAD decryption setup, sg_chain() links the source pages (which are the page cache pages) into the output scatterlist.
Source and destination are now the same physical memory.
The write.
The authencesn algorithm performs Extended Sequence Number rearrangement.
The function crypto_authenc_esn_decrypt() writes seqno_lo (4 bytes from the attacker-controlled AAD) directly into the destination buffer.
Because destination equals source and the source contains page cache references, this writes into the kernel’s cached copy of the target file.
The AEAD tag verification fails afterward because the data is garbage. But it doesn’t matter. The ESN rearrangement fires before tag verification. The corruption is already done.
What the Attacker Controls
The target file is controlled through splice(), which accepts any file descriptor with read permission.
The offset within the file is controlled through the splice file offset combined with the CRYPTLEN parameter.
The 4-byte value written is controlled through AAD bytes 4 through 7 (the seqno_lo field).
That’s a fully controlled, deterministic, arbitrary 4-byte write to any readable file’s page cache. From an unprivileged user.
Reproducing the Primitive
I reproduced the primitive on Kali Linux (kernel 6.18.12, ARM64) by targeting a test file filled with 0x41 bytes and writing 0xDEADBEEF at offset 16.
[+] before: 41414141 ('AAAA')
[+] after : deadbeef
value : 0xDEADBEEF — CONTROLLED WRITE CONFIRMED
The write is deterministic. I ran it 20 times with the same result every time. No race condition, no timing sensitivity, no heap spray. The primitive either works or it doesn’t, and on a vulnerable kernel, it works.
The on-disk file is never modified. Only the kernel’s page cache copy is corrupted. This means standard disk-based integrity monitoring (AIDE, OSSEC, Tripwire) sees nothing. No inotify event is generated. No audit log entry for a file write appears. The corruption exists only in memory.
Why This Is Structurally Different from Dirty Cow and Dirty Pipe
The comparison to Dirty Cow (CVE-2016-5195) and Dirty Pipe (CVE-2022-0847) is inevitable, but the differences are significant.
Dirty Cow required a race condition. You had to win a race between two threads to corrupt a page table entry. This made exploitation probabilistic and sometimes unreliable, especially under load.
Dirty Pipe was more deterministic but still required specific pipe buffer manipulation and had architectural limitations that affected cross-platform portability.
CopyFail requires no race condition at all. The corruption is a direct consequence of the algorithm’s execution path. It works identically on x86_64, ARM64, and every other architecture the kernel supports. The original PoC from Theori is 732 bytes and 10 lines of Python.
The invisibility aspect is also new. Both Dirty Cow and Dirty Pipe could be detected through careful disk forensics. CopyFail corrupts only the page cache. The on-disk file remains pristine. Detection requires live memory forensics, comparing in-memory binary images against on-disk hashes while the system is running.
The Escalation Path
The 4-byte page cache write primitive is the interesting part. The escalation from there to root is straightforward and follows a well-understood pattern: corrupt the page cache of a setuid binary to alter its control flow, then execute it.
I confirmed this path works on my lab system. I’m not publishing the exploit code or the specific binary offsets because the primitive demonstration is the technically interesting contribution, and anyone who understands the primitive can work out the rest.
The AI Discovery Angle
One aspect of this CVE that deserves attention is how it was found.
Taeyang Lee at Theori identified the AF_ALG plus splice interaction as a promising attack surface, then fed the hypothesis to Xint Code, Theori’s AI-driven security scanner. The scan completed in approximately one hour and flagged CopyFail as its highest-severity finding.
Nine years of human code review, kernel security audits, and fuzzing campaigns missed this. An AI scanner found it in sixty minutes.
This doesn’t mean AI replaced the researcher. The human provided the creative hypothesis, the intuition that splice’s zero-copy semantics might interact dangerously with crypto subsystem buffer reuse. The AI performed the exhaustive cross-subsystem analysis that confirmed it. Neither would have found this alone.
For those of us in vulnerability research, this is worth paying attention to. The bugs that survive a decade of human review are exactly the kind that benefit from AI-assisted analysis: cross-subsystem interactions where the dangerous state emerges from the combination of components that were each reviewed in isolation.
Affected Systems and Mitigation
Any Linux kernel from 4.14 onward with CONFIG_CRYPTO_USER_API_AEAD enabled is vulnerable.
This is the default on virtually all major distributions.
The upstream fix (mainline commit a664bf3d603d, April 1, 2026) reverts algif_aead.c to out-of-place operation.
Source and destination are separate scatterlists.
Page cache pages never appear in the writable destination.
If you can’t patch immediately, disabling the vulnerable module is the fastest mitigation:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null
Be aware this may break applications using kernel crypto acceleration, including cryptsetup, Firefox, and IPsec implementations.
For container environments, deploying seccomp policies that block AF_ALG socket creation is an effective hardening measure, since container isolation alone does not protect against kernel-level page cache corruption.
Detection
Standard disk forensics cannot detect exploitation. The on-disk file is never modified.
What works is runtime monitoring. Falco or Sysdig rules can detect suspicious AF_ALG SEQPACKET socket creation from unexpected processes. Live memory forensics can compare in-memory binary images against on-disk hashes. Monitoring for unexpected privilege transitions following kernel crypto syscalls is another viable detection path.
What doesn’t work is anything that relies on the file system. Hash checks, inotify, fanotify, and VFS audit logs all see a clean disk.
Timeline
| Date | Event |
|---|---|
| 2017 | In-place optimization commit 72548b093ee3 introduces the bug |
| April 1, 2026 | Upstream fix committed |
| April 29, 2026 | Public disclosure by Theori |
| April 30, 2026 | CISA adds to Known Exploited Vulnerabilities catalog |
| May 11, 2026 | This independent reproduction and analysis |
Conclusion
CopyFail is a reminder that the most dangerous vulnerabilities aren’t always the most complex. Three reasonable commits, spanning six years, created a primitive that gives any unprivileged user a deterministic 4-byte write to the page cache of any readable file. The fix is a one-line change reverting to out-of-place operation.
What makes it worth studying is the structural lesson. Each component was safe in isolation. The danger emerged from their interaction, specifically from the assumption that buffer reuse is safe when the buffers might contain zero-copy references to shared kernel data structures. That assumption was invisible to anyone reviewing a single subsystem.
Patch your systems. If you run containers, deploy the seccomp mitigation. And if you’re in vulnerability research, spend some time thinking about what other zero-copy plus in-place-operation interactions might be hiding in the kernel. CopyFail probably isn’t the last bug in this class.
Acknowledgments
All credit for the original discovery goes to Taeyang Lee and the team at Theori. Their disclosure and the Xint Code AI-assisted scanning approach represent an important development in how vulnerabilities are found. This post is an independent reproduction and analysis, not an original finding.
References
Theori/Xint, “Copy Fail: 732 Bytes to Root on Every Major Linux Distribution.” Help Net Security, “Nine-year-old Linux kernel flaw enables reliable local privilege escalation.” Tenable, “Copy Fail CVE-2026-31431 FAQ.” The Register, “Linux cryptographic code flaw offers fast route to root.” CERT-EU, Security Advisory 2026-005. Sysdig, “CVE-2026-31431 Copy Fail analysis.”
This research was conducted in an isolated lab environment. All testing was performed on systems owned and operated by the researcher.