Back
cybersecurity

Copy Fail: How a Nine-Year-Old Kernel Optimization Became a Universal Linux Root Exploit

A logic bug buried in the Linux kernel's cryptographic subsystem since 2017 now lets any unprivileged user become root — reliably, silently, and in 732 bytes of Python. Here is exactly how it works, why containers make it worse, and what to do about it.


Every so often a vulnerability comes along that isn't just severe — it changes what you thought you knew. Copy Fail (CVE-2026-31431) is one of those. Disclosed publicly on April 29, 2026 by the security research firm Theori, it is a local privilege escalation flaw in the Linux kernel that works on virtually every major Linux distribution built since 2017. The exploit is a 732-byte Python script. It requires no special privileges to run. It doesn't trigger a race condition. It doesn't crash the system. It just works.

This article explains how — starting from the fundamentals.


What "Local Privilege Escalation" Actually Means

Before getting into the mechanics, here's what this class of vulnerability actually does. Linux enforces a hierarchy of trust. Ordinary users can run programs, read files they own, and interact with the system within a defined boundary. The root user — user ID 0 — has no such boundary. Root can read any file, modify any configuration, kill any process, load kernel modules, and rewrite the rules the system itself runs by.

A local privilege escalation (LPE) vulnerability lets an attacker cross that boundary without authorization. The word "local" is significant: this is not a remote exploit. An attacker needs a foothold on the system first — a shell, even a restricted one. In practice, that foothold is often easier to obtain than people assume: a misconfigured web application, a compromised container workload, a phished developer's SSH credentials. Once you're in, Copy Fail takes you the rest of the way.


Three Reasonable Changes That Became One Unreasonable Outcome

The bug doesn't come from sloppy code. It's the product of three separate kernel changes, each defensible in isolation, that accumulated into a logic flaw over the course of six years.

2011: authencesn is added to the kernel. This is an AEAD (Authenticated Encryption with Associated Data) cryptographic template used by IPsec, the protocol suite that secures IP-level communications. AEAD combines encryption and authentication in a single operation, ensuring that data is both scrambled and verifiably intact. authencesn is a wrapper that handles this for extended sequence numbers — a detail relevant to high-throughput IPsec tunnels.

2015: AF_ALG AEAD socket support arrives. The Linux kernel has a subsystem that exposes hardware-accelerated cryptographic functions to userspace. A program can open an AF_ALG socket, bind it to a cryptographic algorithm — any AEAD template, including authencesn — and ask the kernel to perform encryption or decryption on arbitrary data. No special permissions are required to do this. The feature exists so that applications can offload cryptographic work to the kernel without needing to link against a userspace library.

2017: An in-place optimization is introduced (commit 72548b093ee3). To save memory copies and improve performance, the kernel's algif_aead module is changed to allow encryption to happen in-place: the source memory and destination memory can be the same buffer. This is a standard optimization in cryptographic implementations — there's no reason to allocate a separate output buffer if you can just overwrite the input.

The problem is that this optimization was applied without accounting for what the input might actually be. Specifically, it failed to account for the case where the input is a reference to pages in the kernel's page cache.


The Page Cache: The Invisible Layer Between Files and Processes

This is the mechanism the exploit actually abuses.

When the Linux kernel reads a file from disk, it doesn't hand each read request directly to the storage hardware. Instead, it caches the file's contents in RAM in a structure called the page cache. Subsequent reads of the same file are served from this cache, making them orders of magnitude faster than going back to disk. The page cache is a system-wide resource — it's shared across all processes, including processes running inside containers.

Here's the critical property: when a process executes a program, the kernel loads the program's binary into memory directly from the page cache. The in-memory copy is the page cache. If you could modify the page cache entry for a binary, the next time any process ran that binary, it would execute your modified version — not the original file on disk. The disk file would be untouched. Standard file integrity checks would find nothing wrong.

This is the capability that Copy Fail creates.


How the Exploit Works

The attack chains three kernel primitives: AF_ALG, splice(), and the page cache.

Step 1: splice() loads the target into the scatterlist. The splice() system call transfers data between file descriptors without copying it in userspace — it passes references to the underlying kernel pages. When an attacker splices a readable file (say, /usr/bin/su, the setuid binary that switches users) into a pipe and then into an AF_ALG AEAD socket, the socket's input scatterlist ends up holding direct references to the kernel's page cache pages for that file.

Step 2: authencesn writes back in-place. The attacker invokes an encryption operation using the authencesn(hmac(sha256),cbc(aes)) template. Because of the 2017 in-place optimization, authencesn writes its output back to the same pages it read from — the page cache pages of the target file. As part of handling extended sequence numbers, the algorithm writes four bytes of scratch data at a specific offset. The attacker controls the input to the operation and, with careful construction, lands that 4-byte write at a chosen location within the cached binary.

Step 3: the modified binary yields root. Four bytes is enough. The attacker targets a specific instruction in the cached copy of su (or any other setuid binary) and overwrites it to disable the privilege check. The file on disk is unchanged. But the next invocation of su runs from the modified page cache, skips its own security check, and returns a root shell.

The entire sequence is deterministic. No timing. No retries. No kernel crashes. It works the same way on Ubuntu, Amazon Linux, RHEL, SUSE, Debian, Fedora, and Arch — every distribution running a kernel built since the 2017 optimization was introduced. The working exploit is a 732-byte Python script using only the standard library.


Why This Is Different From Dirty Cow and Dirty Pipe

Security researchers have drawn comparisons to two previous high-profile Linux LPEs.

Dirty Cow (CVE-2016-5195) exploited a race condition in the kernel's copy-on-write memory path. To win the race reliably, the attacker had to run a tight loop hammering two competing threads. It sometimes required multiple attempts and could crash the system. Weaponizing it required care.

Dirty Pipe (CVE-2022-0847) was more elegant but version-specific. It required precise pipe buffer manipulation and only worked on kernels from version 5.8 onward.

Copy Fail has neither limitation. It's a straight-line logic flaw — no race to win, no version-specific offset to calculate. The same script works everywhere. Researchers at Bugcrowd noted that this class of primitive — universal, reliable, portable — is the kind that sells on the zero-day broker market for the price of a house. Crowdfense reportedly runs acquisition programs paying up to $7 million for top-tier Linux primitives. Copy Fail was found by an AI-assisted scanning tool in about an hour.


The Container Escape Angle

For infrastructure teams running container workloads, there's a second layer to this story — and the CVSS 7.8 score undersells it.

Containers share the host kernel. When you run a Docker container or a Kubernetes pod, the container has its own filesystem, its own process namespace, and its own network namespace — but it uses the same Linux kernel as the host and every other container on that node. And the page cache is a kernel resource. It's shared.

This means that a process inside a container that can exploit Copy Fail doesn't just escalate within the container — it can write to the page cache of binaries running on the host or in other containers. The attack surface extends to any shared-kernel multi-tenant environment: Kubernetes nodes, CI/CD runners, shared hosting environments, cloud VMs running containerized workloads.

If your isolation relies entirely on Linux namespaces and cgroups — the standard container model — Copy Fail cuts straight through it. Environments using hardware-level VM boundaries, such as Firecracker microVMs or kernel-sandboxed runtimes like gVisor, are not affected in the same way, because the page cache is not shared across that boundary.

The CERT-EU advisory strongly recommends prioritizing Kubernetes nodes and CI/CD runners for remediation. The Microsoft Defender research team noted that the vulnerability enables cross-container impacts and container escape scenarios, with early signs of exploitation attempts already observed.


Patch Status and Mitigations

CISA added Copy Fail to its Known Exploited Vulnerabilities catalog on May 4, 2026, with a remediation deadline of May 15 for US federal civilian agencies. Patches are available or in active release for most major distributions.

Patch status as of publication:

  • Ubuntu: Fixed for all supported releases before 26.04. Ubuntu 26.04 (Resolute) is not affected.
  • Debian, Fedora, AlmaLinux, SUSE, CloudLinux: Patched kernels available.
  • RHEL: Patch not yet shipped from Red Hat as of this writing. AlmaLinux shipped independently ahead of upstream.
  • Amazon Linux, Arch Linux: Check your distribution's security tracker.

Interim mitigation — non-RHEL systems: If you cannot reboot into a patched kernel immediately, you can disable the algif_aead module:

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

Critical caveat for RHEL-family systems (RHEL, AlmaLinux 8/9, CentOS Stream): The modprobe.d workaround does not work. On these distributions, algif_aead is compiled directly into the kernel (CONFIG_CRYPTO_USER_API_AEAD=y), not as a loadable module. The commands run without error but leave the system unprotected. The CloudLinux team specifically flagged this, noting that applying the modprobe workaround on RHEL-family systems creates a false sense of security. The correct mitigation for these systems is to blacklist the module's init function via GRUB, which requires a reboot but properly closes the attack surface.

What is not affected: dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, and SSH do not use AF_ALG in default configurations and are unaffected by the workaround. To verify whether any running processes are using the affected interface: lsof | grep AF_ALG.


How Xint Code Found a Nine-Year-Old Bug in an Hour

There's a secondary story in Copy Fail's disclosure that doesn't get enough attention. Theori disclosed that the vulnerability was found by their security scanning tool, Xint Code, in roughly one hour of analysis against the Linux kernel's crypto/ subsystem.

A nine-year-old bug in one of the most scrutinized codebases in the world, found in an hour.

Traditional fuzzers are good at finding crashes but tend to miss logic flaws — bugs where individual code paths execute cleanly, but the interaction between them is broken. Xint Code applies an automated reasoning approach rather than mutation-based fuzzing, which is why it caught something fuzzers missed for nine years. Whether that approach scales broadly is still an open question, but the result here is hard to dismiss.

The practical implication: if this class of tool can surface a universal root primitive from the Linux kernel in an hour, the assumption that kernel LPEs are rare and slow to emerge no longer holds. Organizations that deprioritize patching on that basis are taking on more risk than they realize.


What to Do

  • Patch immediately. Check your distribution's security tracker for kernel updates and apply them. For AlmaLinux, Debian, Ubuntu, SUSE, and Fedora, patches are already in production repositories.
  • RHEL users: Do not rely on the modprobe workaround. Apply the GRUB-based mitigation or wait for Red Hat's kernel update, which is expected imminently.
  • Container environments: Patch first on any node that runs untrusted or multi-tenant workloads — Kubernetes nodes, CI runners, shared hosts.
  • Check for exploitation: Because the exploit modifies the page cache without touching disk, standard file integrity monitoring will not catch it. Look for anomalous AF_ALG socket activity (lsof | grep AF_ALG) and unexpected privilege escalation events in your audit logs.
  • Cloud VMs: If you're running EC2, GCE, or Azure VMs with Linux AMIs, check whether your cloud provider's managed AMIs have been updated and redeploy or patch in place accordingly.

CVE-2026-31431 was disclosed by Theori/Xint Code on April 29, 2026. The primary technical writeup is available at xint.io. Patch tracking and vendor advisories are available via NVD and each distribution's security tracker.