Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
copy-fail-CVE-2026-31431 — Copy Fail: 732 Bytes to Root on Every Major Linux Distribution. | Kitploit
Tools/GitHubGitHub/rio128128/copy-fail-cve-2026-31431
Privilege EscalationContainer SecurityExploit FrameworksVulnerability AnalysisExploitationPenetration TestingCloud SecurityRed TeamingBinary Exploitation
GitHubrio128128/copy-fail-cve-2026-31431

copy-fail-CVE-2026-31431

Copy Fail: 732 Bytes to Root on Every Major Linux Distribution.

3 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
View Repository

CVE-2026-31431 — Copy Fail

732 bytes. Any distro. Root.

A straight-line logic flaw in the Linux kernel's authencesn cryptographic template enables an unprivileged local user to perform a precise, controlled 4-byte write into the page cache of any readable file — including setuid binaries. No races. No retries. No recompilation. Root on every major Linux distribution shipped since 2017.

📄 Technical Write-up  ·  🔗 Kernel Patch  ·  🛡️ CVSS: Critical


Tested Distributions

DistroKernel Version
Ubuntu 24.04 LTS6.17.0-1007-aws
Amazon Linux 20236.18.8-9.213.amzn2023
RHEL 10.16.12.0-124.45.1.el10_1
SUSE 166.12.0-160000.9-default

All four were rooted using the identical 732-byte Python script, without modification.


What Makes This Different


Root Cause

The Setup: Page Cache Pages in a Writable Scatterlist

AF_ALG exposes the kernel's crypto subsystem to unprivileged userspace. splice() transfers file data into a pipe by reference — passing page cache pages directly, without copying. When a user splices a file into an AF_ALG AEAD socket, the socket's input scatterlist holds live references to the kernel's cached pages of that file.

In algif_aead.c, the 2017 in-place optimization copied AAD and ciphertext from the TX scatterlist into the RX buffer, but chained the authentication tag pages by reference using sg_chain(), then set req->src = req->dst:

root@kitploit:~
Input SGL:   [ AAD | CT | Tag ]
                              ^
                              └─ sg_chain() → still points to page cache pages

Output SGL:  [ AAD | CT ] ──→ [ Tag (page cache pages) ]
              (RX buffer)       (chained from TX SGL)

req->src ──┐
           ├──→ same combined scatterlist
req->dst ──┘

Page cache pages from splice() were now sitting inside a writable destination scatterlist, separated from the legitimate write region by only an offset boundary. Nothing in the API enforced that algorithms must stay within bounds.

The Trigger: authencesn's Out-of-Bounds Scratch Write

authencesn is an AEAD wrapper used by IPsec for 64-bit Extended Sequence Number (ESN) support. To rearrange ESN bytes for HMAC computation, it uses the caller's destination buffer as scratch space — including a write at offset assoclen + cryptlen, which lies past the authentication tag boundary:

root@kitploit:~
scatterwalk_map_and_copy(tmp,     dst, 0,                       8, 0); // read AAD[0..7]
scatterwalk_map_and_copy(tmp,     dst, 4,                       4, 1); // overwrite dst[4..7]
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen,     4, 1); // ← writes past the tag

The third call writes 4 bytes (seqno_lo) at dst[assoclen + cryptlen]. In the in-place AF_ALG path, the scatterwalk crosses from the RX buffer into the chained page cache tag pages. The kernel maps the page cache page via kmap_local_page and writes directly into the cached copy of the target file.

The HMAC then fails (the ciphertext is fabricated), recvmsg() returns an error — but the 4-byte write persists permanently.

The Three Attacker-Controlled Variables


How It Happened: A Nine-Year Chain

No single change was individually wrong. The vulnerability lives at the intersection of all three.


Exploit

The default target is /usr/bin/su, a setuid-root binary present on all tested distributions.

root@kitploit:~
Step 1 — Socket setup
  Open AF_ALG socket, bind to authencesn(hmac(sha256),cbc(aes))
  Set key. Accept request socket. (No privileges required.)

Step 2 — Write loop (once per 4-byte shellcode chunk)
  sendmsg()  →  AAD bytes [4:8] carry the 4 bytes to write (seqno_lo)
  splice()   →  target file's page cache pages into the AF_ALG socket
  recv()     →  triggers decrypt → authencesn writes seqno_lo into page cache
               (recvmsg returns error; the write persists)

Step 3 — Execute
  execve("/usr/bin/su")
  Kernel loads binary from the (now-corrupted) page cache
  Setuid-root binary executes injected shellcode → UID 0
root@kitploit:~
a = socket.socket(38, 5, 0)                          # AF_ALG, SOCK_SEQPACKET
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
# ... set key, accept request socket u ...
u.sendmsg([b"A"*4 + payload_chunk], [cmsg_headers], MSG_MORE)
os.splice(target_fd, pipe_wr, offset)
os.splice(pipe_rd, alg_fd, offset)
u.recv(...)                                          # triggers page cache write

Remediation

Permanent Fix

Update to a kernel containing patch a664bf3d603d. The fix reverts algif_aead.c to out-of-place operation: req->src points to the TX SGL; req->dst points to the RX buffer. Page cache pages from splice() remain read-only. The sg_chain() mechanism that linked them into the writable destination is removed.

root@kitploit:~
// Before (vulnerable): src and dst share the same scatterlist
aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, rsgl_src, used, ctx->iv);

// After (fixed): src is TX SGL, dst is RX buffer — fully separated
aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, rsgl_dst, used, ctx->iv);

Immediate Mitigation

Disable the algif_aead kernel module:

root@kitploit:~
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null

Or block AF_ALG socket creation via a seccomp policy in your workload profiles.

Note for container environments: Because the page cache is shared across the host, this vulnerability crosses container boundaries. Apply mitigations at the node level, not just per-pod. See Part 2 for full Kubernetes escape details.


Coordinated Disclosure Timeline


Discovery

Theori researcher Taeyang Lee identified, through prior kernelCTF work, that AF_ALG + splice() creates a path where unprivileged userspace can feed page cache pages directly into the crypto subsystem — and that scatterlist page provenance was an underexplored vulnerability class.

The research team used Xint Code to scale this insight across the entire crypto/ subsystem with the following operator prompt:

"This is the linux crypto/ subsystem. Please examine all codepaths reachable from userspace syscalls. Note one key observation: splice() can deliver page-cache references of read-only files (including setuid binaries) to crypto TX scatterlists."

After approximately one hour of automated analysis, Copy Fail was the highest-severity output. Additional vulnerabilities discovered during the same scan remain under coordinated disclosure.


Part 2: From Pod to Host — how Copy Fail escapes every major cloud Kubernetes platform. Coming soon.

Download Tool
PropertyDetail
DeterministicStraight-line logic flaw — no race conditions, no timing windows, no retries
PortableSame script, same bytes, works across all tested distros and architectures
Tiny732-byte Python script using only the standard library (os, socket, zlib). Requires Python 3.10+ for os.splice
StealthyThe corrupted page is never marked dirty. On-disk checksums are unchanged; only the in-memory page cache is modified
Cross-containerThe page cache is shared system-wide across container boundaries — this is also a Kubernetes node escape primitive (see Part 2)
VariableControlled Via
Target fileAny file readable by the current user
Write offsetassoclen, splice offset, and splice length
Write valueBytes 4–7 of the AAD supplied in sendmsg() (seqno_lo)
YearEvent
2011authencesn added to the kernel (a5079d084f8b) for IPsec ESN support. The scratch write existed but was harmless — only the internal xfrm layer called it, and AAD lived in a separate scatterlist.
2015AF_ALG gains AEAD support. authencesn converted to the new AEAD interface (104880a6b470), introducing the assoclen + cryptlen write offset. Still out-of-place: page cache pages were in src (read-only). Not yet exploitable.
2017In-place optimization added to algif_aead.c (72548b093ee3). req->src = req->dst. Page cache tag pages chained into the writable destination. Vulnerability formed.
2026-03-23Reported to the Linux kernel security team.
2026-04-01Patch merged into mainline.
2026-04-22CVE-2026-31431 assigned.
2026-04-29Public disclosure.
DateEvent
2026-03-23Vulnerability reported to Linux kernel security team
2026-03-24Initial acknowledgment received
2026-03-25Patches proposed and reviewed
2026-04-01Patches committed to mainline kernel
2026-04-22CVE-2026-31431 assigned
2026-04-29Public disclosure