Skip to content

Instantly share code, notes, and snippets.

@webcpu
Created April 30, 2026 08:15
Show Gist options
  • Select an option

  • Save webcpu/7c928d4740d4b4330646df1041a5ee1e to your computer and use it in GitHub Desktop.

Select an option

Save webcpu/7c928d4740d4b4330646df1041a5ee1e to your computer and use it in GitHub Desktop.

CVE-2026-31431 (CopyFail)

Local privilege escalation in the Linux kernel's crypto/algif_aead module. Any unprivileged local user can perform a controlled 4-byte write into the page cache of any readable file. Point that write at a setuid binary like /usr/bin/su and you have root. The PoC is 732 bytes of Python. The bug is deterministic, no race condition, no per-kernel offsets. It has been latent in the tree since 2017.

TL;DR

Field Value
CVE ID CVE-2026-31431
Nickname CopyFail / Copy Fail
Product Linux kernel (crypto/algif_aead)
Class Local privilege escalation, page-cache write
CVSS 3.1 7.8 HIGH (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
CWE CWE-669 (Incorrect Resource Transfer Between Spheres)
Introduced Kernel 4.14 (2017), commit 72548b093ee3
Fixed 6.18.22, 6.19.12, 7.0
Disclosed 2026-04-29 by Theori on oss-security
CISA KEV Not listed as of 2026-04-30

Severity & Classification

  • CVSS 3.1 base score 7.8 HIGH from kernel.org as CNA. NVD enrichment still pending. NVD
  • SUSE rates it 5.8 (CVSS v4.0). The discrepancy is the v3 vs v4 framework, not disagreement on impact. SUSE
  • Classified CWE-669 because the bug crosses a privilege sphere: data flows from a writable scratch buffer into the shared page cache, which is supposed to mirror on-disk state. NVD
  • EPSS score under 1% as of disclosure, despite working public PoCs. Expect this to climb. Hacker News thread

Affected Versions

Every mainline Linux kernel from 4.14 (Nov 2017) through unpatched 6.x and early 7.0-rc carries the bug. Nine years of distro builds inherit it: Ubuntu, RHEL, Debian, SUSE, Amazon Linux. oss-security disclosure

uname -r alone is unreliable for triage. Distros backport patches into kernels that keep an old version string. Always check distro changelogs against the CVE ID. Hacker News thread

Root Cause

Two flaws compose to make the exploit work:

  1. In-place AEAD optimization (2017). Commit 72548b093ee3 taught algif_aead.c to set req->src = req->dst and chain pages from splice() into the writable destination scatterlist via sg_chain(). Page-cache pages, including pages backing read-only files, end up in a position the crypto layer treats as scratch memory. Xint/Theori writeup
  2. Authencesn does not clean up after itself. crypto_authenc_esn_decrypt() writes 4 bytes (the seqno_lo field from attacker-controlled AAD) past the legitimate output boundary at dst[assoclen + cryptlen] to rearrange Extended Sequence Number bytes, then never restores them. GCM, CCM, and standard authenc clean up. authencesn does not. oss-security disclosure

Composition: splice delivers page-cache references into the crypto path; authencesn's scratch write lands on those pages. The HMAC verification fails and recvmsg() returns -EBADMSG, but the 4-byte page-cache write has already persisted. The page is never marked dirty, so on-disk checksums stay valid and traditional file integrity tools (AIDE, Tripwire, OSSEC) miss the corruption entirely. Bugcrowd writeup

Exploitation

  • Attack chain: open an AF_ALG socket with authencesn(hmac(sha256),cbc(aes)), splice a target setuid binary into it, position the splice offset so the 4-byte write lands on the chosen instruction, trigger decryption, then exec the corrupted cached binary. Theori PoC
  • Original PoC is 732 bytes of Python. C and Go ports exist. The exploit is simpler than Dirty Pipe (CVE-2022-0847): no race, no timing, no kernel offset leaks. tgies/copy-fail-c, badsectorlabs/copyfail-go
  • Confirmed working on Ubuntu 24.04, Amazon Linux 2023, RHEL 10.1, SUSE 16. Theori PoC
  • Practitioner gotchas in the wild: PoC requires Python 3.10+ for os.splice; on earlier versions it fails silently and gives false negatives. WSL2 cannot be mitigated via modprobe (the module is built in). x86_64-only PoC; ARM needs rewritten shellcode. Slackware's non-world-readable SUID binaries are naturally protected. Hacker News thread

Patches & Fix Commits

The upstream fix reverts the 2017 in-place optimization. Source and destination scatterlists are separated again, so page-cache pages never enter the writable crypto destination.

Branch Fixed Version Commit
mainline 7.0 a664bf3d603d
stable 6.19.x 6.19.12 ce42ee423e58
stable 6.18.x 6.18.22 fafe0fa2995a

Tracked as GHSA-2274-3hgr-wxv6 on GitHub Security Advisories.

Distro Patch Status

Distro Status Tracker
Debian sid Fixed in 6.19.14-1 tracker
Debian bullseye/bookworm/trixie Vulnerable, pending tracker
Ubuntu 22.04 / 24.04 High priority, patches rolling out (137+ pkg combos affected) Ubuntu CVE
Red Hat Advisory page live, details still rendering RHEL CVE
Amazon Linux 2 / 2023 Important, pending fix AWS ALAS
SUSE / openSUSE Affected, pending across product line SUSE CVE

Mitigation (without rebooting)

Disable algif_aead outright. Most workloads never touch it: dm-crypt, LUKS, kTLS, IPsec, and SSH all use the kernel crypto API directly, not the AF_ALG userspace interface. oss-security disclosure

echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead

For RHEL kernels where algif_aead is built in (=y in config) rather than a module, use the kernel boot parameter initcall_blacklist=algif_aead_init instead. Hacker News thread

For container hosts: seccomp filters that block socket(AF_ALG, ...) (family 38) cut off the attack surface for all containers in one go. SELinux policies in enforcing mode have been reported to block exploitation at the algif_aead socket-create step. ByteIota writeup

Detection

No published Sigma, YARA, Snort, or Suricata rules as of 2026-04-30. The attack is in-memory and never touches disk in a way that file-integrity tools can see, so signature work has to focus on syscall patterns. Sesame Disk detection guide

auditd:

-a always,exit -F arch=b64 -S socket -F a0=38 -F a1=5 -k af_alg_watch
-a always,exit -F arch=b64 -S splice -k splice_watch

These are inferred rules, not vendor-published. The signal is AF_ALG socket creation paired with a splice from a SUID binary by a non-root UID within a short window. Sesame Disk detection guide

Falco / eBPF: tracing socket(AF_ALG) plus splice() on /usr/bin/su-like targets is the cleanest detection. No public Falco rule yet. Sesame Disk security explainer

Vulnerability check on a host: Theori's repo includes test_cve_2026_31431.py (exit 0 if patched, 2 if vulnerable). A second checker is at rootsecdev/cve_2026_31431. Theori PoC

Container & Cloud Impact

The page cache is shared host-wide, so a 4-byte write from a container lands in pages backing the host filesystem. Standard container isolation does not help. The default response for hosts that cannot patch immediately is to disable algif_aead on the host and add a seccomp profile blocking AF_ALG for all containers. ByteIota writeup

VM-isolated runtimes (Firecracker, Kata, gVisor) are out of reach because the kernel boundary is real, not just a namespace. Rootless Podman with user namespaces also blocks the easy path because the SUID target inside the user namespace has no real privilege on the host. ByteIota writeup

CISA published an ADP assessment on 2026-04-29 but the CVE is not in the Known Exploited Vulnerabilities catalog as of 2026-04-30. CISA KEV

Timeline

Date Event
2017 (kernel 4.14) Bug introduced via commit 72548b093ee3
2026-03-23 Reported to Linux kernel security team by Theori
2026-03-25 Patches proposed and reviewed
2026-04-01 Fix committed to mainline (commit a664bf3d603d)
2026-04-22 CVE-2026-31431 published
2026-04-29 Public disclosure on oss-security by Jan Schaumann
2026-04-30 Last NVD modification

The Register coverage, oss-security disclosure

Practitioner Notes

  • The discoverer is the offensive-security firm Theori. Their AI scanner "Xint Code" found this in roughly one hour of automated review of the Linux crypto/ subsystem after Taeyang Lee gave it the operator hint that splice() plus page cache was an interesting attack surface. This is one of the cleanest public examples of an AI-assisted CVE in a hardened tree. Bugcrowd writeup
  • Conceptual cousin to Dirty Pipe (CVE-2022-0847) and Dirty Cow (CVE-2016-5195): all three are page-cache write primitives. CopyFail is simpler because there is no race window. Bugcrowd writeup
  • The page-cache primitive is more powerful than the LPE framing suggests. Anything readable to the attacker is corruptible in the cache, including shared library code paths used by other UIDs. SUID is just the obvious target. Xint/Theori writeup

Sources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment