A freshly disclosed Linux kernel flaw nicknamed Copy Fail (CVE-2026-31431) lets any unprivileged local user escalate to root on virtually every mainstream Linux distribution released since 2017. What sets it apart from earlier kernel escalations is its simplicity: no race to win, no compiled payload, and no per-distribution offsets. A 732-byte pure-Python script deterministically corrupts a setuid binary in the page cache and hands back a root shell on Ubuntu, Amazon Linux, RHEL, and SUSE alike. The bug was disclosed by the Xint Code Research Team, building on an initial observation from Theori researcher Taeyang Lee, and it carries serious implications for containerized and Kubernetes deployments.

What makes Copy Fail different

Copy Fail is a logic error in the kernel's authencesn cryptographic template, part of the AEAD (Authenticated Encryption with Associated Data) subsystem. The defect lets an attacker drive a deterministic, fully controlled 4-byte write into the page cache of any file they can read — with zero write permission on the target.

Earlier marquee privilege-escalation bugs demanded real effort. Dirty Cow (CVE-2016-5195) hinged on winning a VM-subsystem race, often needed several tries, and could crash the box along the way. Dirty Pipe (CVE-2022-0847) was tied to specific kernel versions and required careful pipe-buffer manipulation. Copy Fail discards all of that:

  • Deterministic — it is a straight-line logic bug. No races, no retries, no timing windows.
  • Portable — one unmodified Python script works across Ubuntu, Amazon Linux, RHEL, and SUSE on every architecture tested, with no offset tuning or recompiling.
  • Minimal — the whole exploit is a short script that imports only os, socket, and zlib from the standard library. It needs Python 3.10+ for os.splice, and nothing is compiled or installed.
  • Stealthy — the kernel never flags the modified page as dirty, so no writeback occurs. Because the on-disk file is untouched, hash- and checksum-based integrity tools see nothing; only the in-memory page cache changes.
  • Cross-container — since the page cache is shared by every process on a host, including across container boundaries, this is not merely a local escalation but also a container-escape primitive and a path to compromising a Kubernetes node.

Root cause: page cache pages inside a writable scatterlist

AF_ALG is a Linux socket family that surfaces the kernel crypto subsystem to unprivileged userspace. Any user can open an AF_ALG socket, bind it to an AEAD template, and run encrypt/decrypt operations on data of their choosing — no privileges needed.

The exploit stitches together two kernel primitives. The first is splice(), which moves data between file descriptors and pipes by reference instead of copying. When a user splices a readable file into a pipe and then into an AF_ALG socket, the socket's input scatterlist ends up pointing directly at the kernel's cached pages of that file. Those entries are not duplicates — they reference the very physical memory that backs every read(), mmap(), and execve() of the file across the whole system.

For AEAD decryption the input is laid out as AAD (associated authenticated data), then ciphertext, then an authentication tag. Inside algif_aead.c, the kernel's recvmsg() configures the operation in-place, so a single scatterlist acts as both input and output. The AAD and ciphertext are duplicated into the output buffer through memcpy_sglist — a genuine copy that only reads the cached pages. The trailing authentication tag, however, is not copied. Instead the kernel splices those tag scatterlist entries onto the output scatterlist with sg_chain().

The outcome is an output scatterlist made of two regions: a legitimate, user-controlled receive buffer holding the copied AAD and ciphertext, followed by chained tag pages that still reference the original page cache pages of the target file. Both req->src and req->dst point at the head of this combined chain. Page cache pages now live inside a writable scatterlist, separated from the intended write region by nothing more than an offset boundary that no mechanism enforces.

The trigger: authencesn's scratch write

The AEAD decryption API carries an unwritten contract: the destination buffer receives only plaintext output, and nothing beyond it is written. Every AEAD algorithm is expected to respect that line. The API neither enforces it nor documents it as a hard rule.

authencesn quietly violates this invariant. During decryption it makes a tiny 4-byte scratch write at a position computed relative to the start of its scatterlist. Once the tag pages have been chained onto the output scatterlist as described, that scratch write lands inside the page cache of the spliced-in file rather than in the user's receive buffer. The write is deterministic: by controlling the splice offset and the authentication-tag length, the attacker dictates exactly where those 4 bytes fall within the file's cached pages.

An unprivileged user can aim this at the page cache of a setuid binary such as /usr/bin/sudo or /bin/su. Flipping 4 bytes at the right offset alters the binary's in-memory behavior while leaving the on-disk copy intact. Because execve() reads from the page cache, the tampered version runs immediately, system-wide, for anyone who invokes the binary.

Proof of concept

A public PoC is available at JuanBindez/CVE-2026-31431, alongside the researchers' write-up at copy.fail. The core of the technique is binding an AF_ALG socket to the vulnerable authencesn template:


a = s.socket(38, 5, 0)  # AF_ALG = 38 (kernel crypto interface)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))

The key-setup and option calls prime the crypto request — the supplied key material acts as the trigger:


v(h, 1, d('0800010000000010'+'0'*64))  # option 1
v(h, 5, None, 4)                        # option 5 (NULL payload)

The operation is then driven through sendmsg() with ancillary control messages, where the per-iteration counter i varies the sizes:


u.sendmsg([b"A"*4+c], [
    (h, 3, i*4),           # cmsg level 3 (ALG_OP?)
    (h, 2, b'\x10'+i*19),  # cmsg level 2
    (h, 4, b'\x08'+i*3)    # cmsg level 4
], 32768)

Finally, splice() zero-copies the target file's cached pages into the socket via an anonymous pipe, placing those page cache pages into the writable scatterlist:


r, w = g.pipe()           # create anonymous pipe
g.splice(f, w, o, offset_src=0)      # copy from file to pipe
g.splice(r, u.fileno(), o)           # copy from pipe to socket

If the exploit succeeds, running id from the spawned shell shows root, confirming privilege escalation.

Affected systems and scope

Both the authencesn template and the AF_ALG socket interface have shipped in the mainline kernel since at least 2017, so any distribution carrying a kernel from that era onward is exposed if it enables AF_ALG — which is essentially the default everywhere. Confirmed affected platforms include:

  • Ubuntu (all supported LTS and non-LTS releases)
  • Amazon Linux 2 and Amazon Linux 2023
  • Red Hat Enterprise Linux (RHEL) and CentOS Stream
  • SUSE Linux Enterprise and openSUSE

The shared nature of the page cache magnifies the danger in cloud and enterprise estates. Because the cache spans namespaces, an unprivileged process inside a container can corrupt the page cache of the host's setuid binaries, escaping the container without exploiting any container-runtime bug. Kubernetes node compromise follows directly; Xint Code says Part 2 of its disclosure series will detail that attack path.

Detection and stealth

Conventional file-integrity monitoring that hashes on-disk content — including AIDE, Tripwire, and most EDR filesystem watchers — will miss a Copy Fail attack outright. The inode and file data on disk are never written, the kernel never marks the affected page dirty, so no write I/O is issued and no journal entry is created. What little defenders can observe is limited to:

  • AF_ALG socket creation followed by unusual splice sequences in syscall traces
  • In-memory page cache integrity checks, which most tools do not perform
  • eBPF-based monitoring of algif_aead operations correlated with splice syscalls against executable files

If a system has been reachable by local unprivileged users and remains unpatched, organizations that rely solely on file-hash baselines should treat it as potentially compromised.

Remediation

The upstream fix addresses the root cause directly. Per the NVD entry and the CVE record, published April 22, 2026, the resolution is "crypto: algif_aead - Revert to operating out-of-place," which reverts the in-place behavior so authencesn no longer writes outside its designated output buffer during decryption, eliminating the out-of-bounds scratch write. Kernel maintainers have accepted the patch and distributions are pushing updates through their normal security channels.

Given that the exploit has no prerequisites and a public PoC exists, treat patching as urgent on any multi-user or container-hosting system. On most distributions, update the kernel and reboot:


# Ubuntu/Debian
sudo apt update
sudo apt upgrade -y

# RHEL-based systems
sudo yum update

For organizations that cannot patch immediately, a temporary option is to block the affected module:


echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true

Additional interim mitigations:

  • Restrict AF_ALG socket creation with seccomp filters or LSM policies where practical
  • Apply kernel live-patching if your distribution supports it
  • Watch EDR or auditd logs for unusual AF_ALG + splice syscall combinations
  • Limit local shell access on sensitive or multi-tenant hosts until patching is finished

How it was found: AI-assisted research

Copy Fail emerged from AI-assisted vulnerability research. Theori researcher Taeyang Lee began by examining how the Linux crypto subsystem handles page-cache-backed data, then used Xint Code to scale that analysis across the whole crypto subsystem; Copy Fail was the most severe finding in the resulting report. As the Xint Code write-up describes, it is an early, concrete example of AI tooling meaningfully accelerating deep kernel research — something defenders and attackers alike should expect more of.

Bottom line

CVE-2026-31431 ranks among the most consequential Linux privilege-escalation bugs in years. Its mix of portability, determinism, stealth, and cross-container reach makes it a top remediation priority for anything from a single server to a large Kubernetes fleet. A 732-byte script now sets a strikingly low bar between an unprivileged shell and root, and because the corruption never touches disk, teams leaning only on file-integrity tooling are effectively blind. Patch now, watch for AF_ALG abuse, and keep an eye out for Part 2 of Xint Code's disclosure covering the full Kubernetes node-escape chain.