
Exploit and detector for a Linux kernel local privilege escalation (CVE-2026-31431) that corrupts page cache to gain root, with mitigation guidance.
A critical 9-year-old flaw in the Linux kernel that allows obtaining root access in seconds
| Attribute | Details |
|---|---|
| CVE | CVE-2026-31431 |
| Nickname | Copy Fail |
| Type | Local Privilege Escalation (LPE) |
| CVSS | 7.8 (High) |
| Discovered by | Theori (Xint Code) |
| Disclosure | April 29, 2026 |
| Component | Linux kernel algif_aead subsystem |
Flaw in the "in-place operation" optimization introduced in 2017 (commit 72548b093ee3). It allows a local user to perform a controlled 4-byte write directly into the kernel's page cache.
AF_ALG interface to access kernel cryptographic algorithms/usr/bin/su) or sensitive files (/etc/passwd)It is a logical design bug, not a memory overflow. It required deep analysis of the cryptographic subsystem to detect it.
# Ubuntu/Debian
sudo apt update
sudo apt upgrade
sudo reboot
# RHEL/AlmaLinux/Rocky
sudo dnf update kernel
sudo reboot
# Verify kernel version
uname -r
⚠️ Reboot is mandatory to activate the new kernel.
# Disable loading of the vulnerable module
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/copyfail_mitigation.conf
# Unload the module if already in use
sudo rmmod algif_aead
# The module is usually built into the kernel
# Add boot parameter to disable it
sudo grubby --update-kernel=ALL --args="initcall_blacklist=algif_aead_init"
# Reboot to apply changes
sudo reboot
# Purge page cache on the fly
sudo sysctl -w vm.drop_caches=3
⚠️ Note: This does not replace the patch. It is only a complementary measure.
| Date | Event |
|---|---|
| April 29 | Public disclosure by Theori |
| May 1 | First active exploitation attempts detected |
# Get kernel version
uname -r
# Vulnerable if:
# - v4.14 to v7.0-rc (released between 2017 and April 2026)
# - Contains commit 72548b093ee3
# Check if the algif_aead module is loaded
lsmod | grep algif_aead
# If it appears in the list, your system is vulnerable
An AI identified this flaw that went unnoticed by developers for 9 years. This marks a before and after:
# 1. Detect
python3 prueba.py
# exit 0 = not vulnerable, 2 = vulnerable, 1 = test error
# 2. Exploit (interactive — su will prompt for your own password)
python3 exploit.py --shell
python3 prueba.py
What it does:
Confirms that AF_ALG and the algorithm authencesn(hmac(sha256),cbc(aes))
are accessible from an unprivileged process.
Creates a 4 KiB sentinel file in a temporary directory and fills the page cache.
Sends 8 bytes of in-line AAD via sendmsg+cmsg with seqno_lo set to
the PWND marker, then copies 32 bytes from the sentinel's page cache page into the AF_ALG operation socket via os.splice().
Calls recv() to initiate decryption. The authentication check fails with
EBADMSG; the temporary write is performed anyway.
Re-reads the file (page cache, not disk) and looks for the marker.
Output classes:
Precondition not met: AF_ALG or authencesn not available. Exit 0.VULNERABLE to CVE-2026-31431: the PWND marker was inserted into the modified page.Exit 2.
Page cache MODIFIED via an in-place AEAD insertion path: the page was written to,
but the marker was not inserted at the expected position.
Treat as vulnerable. Exit 2.Page cache intact: patched. Exit 0.The detector never modifies /usr/bin/su, /etc/passwd, or any other file outside the temporary directory it creates, and that file is removed upon completion.
Exit. ## LPE usage
python3 exploit_cve_2026_31431.py # Only patches, prints next steps
python3 exploit_cve_2026_31431.py --shell # Patches and runs `su <user>`
Function:
/etc/passwd and finds thebyte offset of the 4-character UID field.
write4 at that offset, replacing the UID with0000.
pwd.getpwnam(user) to confirm that libc now reports UID 0.--shell, runs execvp("su", ["su", user]). Enter your own
password. PAM validates against /etc/shadow (unmodified), thensetuid(getpwnam(user).pw_uid) is set to 0.
require multi-shot writes; extend write4 accordingly.
No NSS cache daemon (nscd, sssd, systemd-userdbd) is masking
/etc/passwd reads. If getpwnam still returns the real UID after
the patch is applied, restart or ignore the cache, or select a different user.
The /etc/passwd page must remain in cache between applying the patch and
running su. In practice, this is reliable on any system with normal memory pressure.
The /etc/passwd file on disk remains unchanged.
The dry run (exploit_cve_2026_31431.py without --shell) automatically removes
the corrupted page upon exit via POSIX_FADV_DONTNEED, so UID → name lookups
return to normal immediately.
After using --shell**, the page remains corrupted until cleared.
While corrupted, any operation that resolves UID 1000 → name (e.g., ls,
file managers, scp/sftp ownership checks) will fail or show numeric identifiers. To clear it:
# Without privileges: request page cache eviction for /etc/passwd:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); \
os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
# From the root console:
echo 3 > /proc/sys/vm/drop_caches
A reboot also clears it.
write4 workssendmsg([8-byte AAD], cmsg=[ALG_SET_OP=DECRYPT, ALG_SET_IV, ALG_SET_AEAD_ASSOCLEN=8],
flags=MSG_MORE)
splice(target_fd, pipe_w, 32, offset_src=file_offset)
splice(pipe_r, op_fd, 32)
recv(op_fd) # EBADMSG; the temporary write has already been performed
The 4 bytes at positions 4 to 7 of the AAD (seqno_lo) are written by
authencesn into the destination scatterlist, which in this code path
is the page cache page we extracted from target_fd. The landing offset
within the page corresponds to the offset_src we passed to splice().
Until the patched kernel reaches your distribution:
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
After applying the patch, test_cve_2026_31431.py should show the message «Precondition
not met» and exit with code 0.
The original fix reverts in-place AEAD operations to out-of-place operations, keeping page cache pages out of modifiable scatterlists.
algif_aeadalgif_aead module in audit logsLast updated: May 3, 2026
Status: 🔴 CRITICAL - Immediate action required
| May 2 | CISA orders US federal agencies to patch before May 15 |
| May 3 | Patches available in Ubuntu, RHEL, AlmaLinux, Debian |
| Distribution | Status | Reference |
|---|
| Ubuntu | ✅ Patched | USN-8226-1 (20.04, 22.04, 24.04) |
| RHEL/AlmaLinux/Rocky | ✅ Available | Since May 1 |
| Debian | ✅ In security repositories | Update available |
| Android | ⏳ Coming soon | June 2026 security bulletin |