On April 29th, CVE-2026-31431, dubbed “CopyFail”, was publicly disclosed. The vulnerability had been sitting in the kernel for 9 years — since 2017. It allows any local user to gain root. No race conditions, no offset guessing, 100% reliability. The entire exploit fits in a 732-byte Python script.

What’s Affected

The algif_aead module in the kernel’s crypto subsystem (AF_ALG). Affects virtually every distribution with a kernel built since 2017:

  • Ubuntu 20.04 – 24.04
  • RHEL 10.1
  • Amazon Linux 2023
  • SUSE 16
  • Debian, Fedora, Arch, Rocky Linux, AlmaLinux

CVSS: 7.8 (HIGH) — local access, low privileges, no user interaction required.

How It Happened

The vulnerability emerged from three independent changes, each reasonable on its own:

2011 — the authencesn algorithm was added for IPsec Extended Sequence Numbers. It uses the destination buffer as scratch space, writing 4 bytes (seqno_lo) past the authentication tag area.

2015 — AF_ALG gained AEAD support with splice() capability. Operations were out-of-place — separate source and destination scatterlists.

2017 — an optimization in algif_aead.c (commit 72548b093ee3) set req->src = req->dst (in-place operation). From this point, page cache pages ended up in the writable destination scatterlist.

Exploit Mechanism

The attack exploits the fact that splice() passes direct references to page cache pages to the kernel — not copies. After the 2017 optimization, the output scatterlist chains these pages via sg_chain().

The authencesn algorithm writes 4 bytes of scratch data at an attacker-controlled offset. Those 4 bytes land directly in the page cache of a chosen file.

The attacker controls:

  • Target file — any file readable by the current user
  • Write offset — via splice parameters (offset, length, assoclen)
  • Write value — 4 bytes of seqno_lo come from AAD bytes 4–7 in sendmsg()

Step by step:

  1. Open an AF_ALG socket, bind to authencesn(hmac(sha256),cbc(aes))
  2. For each 4-byte chunk of shellcode — construct a sendmsg() + splice() pair targeting /usr/bin/su
  3. recv() triggers decryption, authencesn writes data into page cache pages
  4. execve("/usr/bin/su") loads the corrupted binary from page cache — shellcode runs as root

The kernel never marks the corrupted page as dirty, so the on-disk file stays untouched. File integrity tools checking on-disk content will detect nothing.

What This Means in Practice

  • Any unprivileged local user can become root
  • Works across container boundaries — page cache is shared
  • Bypasses on-disk file integrity checks
  • 100% deterministic — no race conditions, no retries
  • At the time of disclosure, no distribution had shipped a fixed kernel package

The Fix

The kernel fix (commit a664bf3d603d) reverts algif_aead.c to out-of-place operation. req->src points to the TX SGL (which may contain page cache pages from splice), while req->dst points to the RX SGL (user’s recvmsg buffer). The sg_chain mechanism linking page cache pages into writable destinations is eliminated.

How to Protect Yourself Now

Before your distribution ships a patched kernel, block the algif_aead module:

cat > /etc/modprobe.d/disable-algif.conf << 'EOF'
blacklist algif_aead
install algif_aead /bin/false
EOF

If the module is already loaded:

lsmod | grep algif_aead

If it is — you need a reboot or to unload the module (if nothing is using it).

In containerized and Kubernetes environments, additionally block AF_ALG socket creation via seccomp. Prioritize nodes exposed to untrusted workloads and CI/CD runners.

Check If You’re Vulnerable

The Theori team published a test script test_cve_2026_31431.py — returns exit code 0 if patched, 2 if vulnerable.

You can also check manually:

uname -r
modprobe -n algif_aead 2>&1

If the module can be loaded and your kernel is from 2017–2026 (before the fix) — the system is vulnerable.


Sources: copy.fail, Xint Code, NVD, CERT-EU, GitHub PoC