
Multi-language educational exploit implementations for CVE-2026-31431, a Linux kernel local privilege escalation via the algif_aead module, with a safe detector and CTF usage guidance.
Educational repository with multi-language implementations of the Copy Fail exploit.
Created and maintained by @shotafry — because reading the CVE is not enough. You have to reproduce it.
Copy Fail is a local privilege escalation (LPE) vulnerability in the Linux kernel, catalogued as CVE-2026-31431. It affects the kernel's cryptographic subsystem, specifically the algif_aead module that handles authenticated encryption (AEAD) operations through AF_ALG sockets.
The bug was introduced in 2017 as part of an optimization in the authencesn module and went undetected for nearly 9 years, present in virtually every modern Linux distribution.
What makes Copy Fail special compared to other historical LPEs:
| Feature | Copy Fail | Typical LPE |
|---|---|---|
| Requires race condition | ❌ No | ✅ Yes |
| Requires kernel-specific offset | ❌ No | ✅ Yes |
| Works across all distros | ✅ Yes | ❌ Usually not |
| Reliability | 100% deterministic | Variable |
| Modifies disk | ❌ No (RAM only) | Depends |
The vulnerability was discovered by Taeyang Lee from Theori's research team. The full exploit chain was developed by the Xint Code Research team, who documented the process using AI-assisted analysis of the Linux kernel's crypto/ subsystem.
The public disclosure includes a functional PoC, complete technical analysis and documentation at copy.fail.
CVE: CVE-2026-31431
CVSS: 7.8 — HIGH
Vector: Local
Impact: Full privilege escalation (root)
Distros: All Linux distributions with kernel >= 2017 (unpatched)
The CVSS score is 7.8 and does not reach critical (9+) solely because it requires prior local access — the attacker must already have a session on the system. In cloud environments and with Docker containers, this requirement is considerably easier to meet than it appears.
The Linux kernel stores recently read files in RAM. This is called the page cache. When a process reads /etc/passwd, the kernel does not go to disk — it serves the in-memory copy. This is faster, but creates an attack surface: if you can modify that RAM copy without touching the disk, the system will see falsified data.
The algif_aead module allows AEAD operations from user space via AF_ALG sockets. The bug lies in the 2017 optimization: when splice() is used to pass pages from a file into the socket, those page cache pages end up in the destination (writable) scatter-gather list of the cryptographic operation.
Result: any unprivileged user can write 4 controlled bytes into any file they can read, without touching the disk.
Unprivileged user
│
▼
Opens AF_ALG socket (authencesn)
│
▼
sendmsg() — AEAD parameters with our 4 bytes in seqno_lo
│
▼
splice() — file → pipe → op socket
[BUG] The file's page cache pages end up in the destination scatterlist
│
▼
recv() triggers the AEAD operation
Auth check fails (EBADMSG) but the scratch-write already happened
│
▼
/etc/passwd (page cache) now says: user → UID 0
│
▼
su <user> → PAM validates real password → setuid(0) → ROOT
Imagine the kernel has a castle registry book (/etc/passwd). Copy Fail is like discovering that if you open the castle's magic workshop in a very specific order, the registry book accidentally ends up on your workbench — and you can change your rank from "foot soldier" to "king" with a pen. The clerk (PAM) checks your password but doesn't check the original book, only the copy in front of them. You're king.

>= ~2017 without the CVE-2026-31431 patchalgif_aead module available and loadable# Check kernel version
uname -a
# Check if the algorithm is available
grep -i authencesn /proc/crypto
# Check if the module is loaded
lsmod | grep alg
If grep -i authencesn /proc/crypto returns authencesn(hmac(sha256),cbc(aes)), the system is vulnerable.
| Language | Target requirement | Pre-compilation needed |
|---|---|---|
| C | None (static binary) | gcc on build machine |
| Python | Python 3.10+ | No |
| Rust | None (static binary) | rustc on build machine |
| Go | None (static binary) | go on build machine |
| Ruby | Ruby + fiddle gem (included by default) | No |
| Perl | Perl 5 (present on virtually all Linux) | No |
This repository contains the exploit implemented in 6 languages, all functionally equivalent, with educational comments in Spanish.
copy_fail_exploit.c → C — static binary, zero dependencies
copy_fail_exploit.py → Python — most readable, ideal for learning
copy_fail_exploit.rs → Rust — the irony: "safe" language exploits kernel
copy_fail_exploit.go → Go — static binary, highly portable
copy_fail_exploit.rb → Ruby — ubiquitous on Rails servers
copy_fail_exploit.pl → Perl — the quietest, present on all Linux
test_cve_2026_31431.py → Detector — checks vulnerability without exploiting anything
python3 test_cve_2026_31431.py
gcc copy_fail_exploit.c -o copy_fail_c
./copy_fail_c # dry-run (cleans up, leaves no trace)
./copy_fail_c --shell # full exploit
python3 copy_fail_exploit.py
python3 copy_fail_exploit.py --shell
rustc copy_fail_exploit.rs -o copy_fail_rs
./copy_fail_rs
./copy_fail_rs --shell
go build -o copy_fail_go copy_fail_exploit.go
./copy_fail_go
./copy_fail_go --shell
ruby copy_fail_exploit.rb
ruby copy_fail_exploit.rb --shell
perl copy_fail_exploit.pl
perl copy_fail_exploit.pl --shell