[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fKci7gEcvo7lbvAScletgFLNqsIybK-uDal5FPtw7OS0":3},{"article":4,"iocs":44},{"id":5,"title":6,"slug":7,"summary":8,"ai_summary":9,"brief":10,"full_text":11,"url":12,"image_url":13,"published_at":14,"ingested_at":15,"relevance_score":16,"entities":17,"category_id":33,"category":34,"article_tags":38},"7f26ccee-2ba2-4452-bc54-791c7bddcbf6","Copy Fail: 732 Bytes to Root on Every Major Linux Distributions - Xint","copy-fail-732-bytes-to-root-on-every-major-linux-distributions-xint-daedc6","Xint Code disclosed CVE-2026-31431, an authencesn scratch-write bug chaining AF_ALG + splice() into a 4-byte page cache write. A 732-byte PoC gets root on Ubuntu, Amazon Linux, RHEL, SUSE. | AI for Security, Vulnerability Research","Xint Code disclosed CVE-2026-31431, a logic bug in the Linux kernel's authencesn cryptographic template that allows unprivileged local users to trigger a controlled 4-byte page cache write. A portable 732-byte Python PoC exploits the flaw to achieve root privilege escalation on Ubuntu, Amazon Linux, RHEL, SUSE, and other major distributions since 2017, and can also escape container boundaries.","CVE-2026-31431 allows unprivileged users to gain root via 732-byte PoC on major Linux distributions.","AI for Security Vulnerability ResearchCopy Fail: 732 Bytes to Root on Every Major Linux Distribution.Xint Code disclosed CVE-2026-31431, an authencesn scratch-write bug chaining AF_ALG + splice() into a 4-byte page cache write. A 732-byte PoC gets root on Ubuntu, Amazon Linux, RHEL, SUSE.Apr 29, 2026ContentsWhat Makes Copy Fail DifferentThe Root Cause: Page Cache Pages in the Writable ScatterlistThe Trigger: authencesn's Scratch WriteHow This HappenedThe ExploitThe DemoThe FixRemediationCoordinated Disclosure TimelineHow We Found ItCopy Fail: 732 Bytes to Root on Every Major Linux Distribution.Xint Code Research TeamCopy Fail (CVE-2026-31431) is a logic bug in the Linux kernel's authencesn cryptographic template. It lets an unprivileged local user trigger a deterministic, controlled 4-byte write into the page cache of any readable file on the system. A single 732-byte Python script can edit a setuid binary and obtain root on essentially all Linux distributions shipped since 2017.The kernel never marks the corrupted page dirty for writeback, so the file on disk remains unchanged and ordinary on-disk checksum comparisons miss the modification. However, the page cache is what actually gets read when accessing the file, so the corrupted in-memory version is immediately visible system-wide. A local unprivileged user can turn this into root by corrupting the page cache of a setuid binary. The same primitive also crosses container boundaries because the page cache is shared across the host.This finding was AI-assisted, but began with an insight from Theori researcher Taeyang Lee, who was studying how the Linux crypto subsystem interacts with page-cache-backed data. He used Xint Code to scale his research across the entire crypto subsystem, and Copy Fail was the most critical finding in the report.This is the first in a two-part series:Part 1 (this post): The bug and local privilege escalationPart 2: Kubernetes container escapeWhat Makes Copy Fail DifferentThe Linux kernel has had high-profile privilege escalation bugs before. Dirty Cow (CVE-2016-5195) required winning a race condition in the VM subsystem's copy-on-write path. It often needed multiple attempts and sometimes crashed the system. Dirty Pipe (CVE-2022-0847) was version-specific and required precise pipe buffer manipulation.Copy Fail is a straight-line logic flaw. It triggers without races, retries, or crash-prone timing windows.Portable. The same exact script works on every tested distribution and architecture, including Ubuntu, Amazon Linux, RHEL, and SUSE. No per-distro offsets. No recompilation. No version checks in the exploit.Tiny. The entire exploit is a short Python script using only standard library modules (os, socket, zlib). It requires Python 3.10+ for os.splice. No compiled payloads, no dependency installation.Stealthy. The write bypasses the ordinary VFS write path. The corrupted page is never marked dirty by the kernel's writeback machinery. Standard file integrity tools comparing on-disk checksums will miss it, because the on-disk file is unchanged. Only the in-memory page cache is corrupted.Cross-container impact. The page cache is shared across all processes on a system, including across container boundaries. Copy Fail is not just a local privilege escalation. It is a container escape primitive and a Kubernetes node compromise vector (Part 2).The Root Cause: Page Cache Pages in the Writable ScatterlistAF_ALG is a socket type that exposes the kernel's crypto subsystem to unprivileged userspace. A user can open a socket, bind to any AEAD (Authenticated Encryption with Associated Data) template, and invoke encryption or decryption on arbitrary data. No privileges required.A core primitive underlying this bug is splice(): it transfers data between file descriptors and pipes without copying, passing page cache pages by reference. When a user splices a file into a pipe and then into an AF_ALG socket, the socket's input scatterlist holds direct references to the kernel's cached pages of that file. The pages are not duplicated; the scatterlist entries point at the same physical pages that back every read(), mmap(), and execve() of that file.For AEAD decryption, the input is AAD (associated authenticated data) || ciphertext || authentication_tag. Inside algif_aead.c, recvmsg() sets up the operation as in-place, meaning the same scatterlist serves as both input and output for the crypto algorithm.The AAD and ciphertext data are byte-copied from the input scatterlist into the output buffer via memcpy_sglist. This is a real copy. The page cache pages are only read. But the authentication tag, the last authsize bytes of the input scatterlist, is not copied. The kernel retains the scatterlist entries for the tag and chains them onto the end of the output scatterlist using sg_chain():Input SGL: AAD || CT || Tag | | ^ | copy | | sg_chain (still references page cache pages) v v | Output SGL: AAD || CT -----+The output scatterlist now has two regions: the user's recvmsg buffer (containing copied AAD and ciphertext), followed by the chained tag pages, still referencing the original page cache pages of the target file. The kernel sets req->src = req->dst, both pointing to the head of this combined chain:req->src ----+ | v req->dst --> [ AAD || CT ] --> [ Tag (page cache pages) ] | | | | +-- RX buffer ---+ +-- chained from TX SGL -+ | (user mem) | (file's page cache)This in-place design is the root cause of the vulnerability. It places page cache pages in a writable scatterlist, separated from the legitimate write region by nothing more than an offset boundary. The design assumes every AEAD algorithm will confine its writes to the intended destination, but nothing in the API enforces this, and nothing documents it as a requirement.Unfortunately, one AEAD algorithm breaks this silent invariant.The Trigger: authencesn's Scratch WriteThe kernel's AEAD API defines a clear output contract for decryption: the destination buffer receives AAD || plaintext, exactly assoclen + (cryptlen - authsize) bytes.authencesn is an AEAD wrapper used by IPsec for Extended Sequence Number (ESN) support. IPsec uses 64-bit sequence numbers split into a high half (seqno_hi, bytes 0–3 of the AAD) and a low half (seqno_lo, bytes 4–7). The wire format carries only seqno_lo; seqno_hi is implicit. For HMAC computation, authencesn needs to rearrange these bytes: seqno_hi at the front of the hash input, seqno_lo appended at the end.It performs this rearrangement by using the caller's destination buffer as scratch space. In crypto_authenc_esn_decrypt():scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); \u002F\u002F read AAD bytes 0–7 scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); \u002F\u002F overwrite dst[4..7] with seqno_hi scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); \u002F\u002F write seqno_lo after the tagThe first two calls shuffle the ESN bytes within the AAD region, a temporary modification that gets restored. The third call writes 4 bytes at offset assoclen + cryptlen, past the AEAD tag. The algorithm is using memory it does not own as a scratch pad.The original bytes at that position are permanently lost. crypto_authenc_esn_decrypt_tail() reads seqno_lo back to reconstruct the AAD, but never writes the original content back to dst[assoclen + cryptlen]. The position is treated as expendable scratch, regardless of whether the operation succeeds or fails.No other standard AEAD algorithm in the kernel does this. GCM, CCM, and regular authenc all confine their writes to the legitimate output area. authencesn alone writes past the boundary.In the AF_ALG in-place path, this write crosses from the output buffer into the chained page cache tag pages. scatterwalk_map_and_copy walks past the RX buffer, maps the page cache page via kmap_local_page, and writes seqno_lo directly into the kernel's cached copy of the target file. The HMAC computation then runs and fails (the ciphertext is fabricated), so recvmsg() returns an error, but the 4-byte contr","https:\u002F\u002Fxint.io\u002Fblog\u002Fcopy-fail-linux-distributions","https:\u002F\u002Finblog.ai\u002Fapi\u002Fog?title=Copy%20Fail%3A%20732%20Bytes%20to%20Root%20on%20Every%20Major%20Linux%20Distributions&logoUrl=https%3A%2F%2Fsource.inblog.dev%2Flogo%2F2026-04-21T20%3A39%3A21.712Z-fe202dd0-0a7f-41d2-a9bd-88052b6a6250&blogTitle=","2026-04-29T19:58:59+00:00","2026-04-29T20:00:11.228+00:00",9,[18,21,24,26,28,30],{"name":19,"type":20},"Linux kernel","technology",{"name":22,"type":23},"Ubuntu","product",{"name":25,"type":23},"Amazon Linux",{"name":27,"type":23},"RHEL",{"name":29,"type":23},"SUSE",{"name":31,"type":32},"Xint Code","vendor","80544778-fabb-4dcd-aa35-17492e5dcf4f",{"id":33,"icon":35,"name":36,"slug":37},null,"Vulnerabilities","vulnerabilities",[39],{"category":40},{"id":41,"icon":35,"name":42,"slug":43},"574f766a-fb3f-487c-8d2c-0720ae75471b","Zero-day","zero-day",[45,49],{"type":46,"value":47,"context":48},"cve","CVE-2026-31431","Logic bug in Linux kernel authencesn cryptographic template enabling privilege escalation",{"type":50,"value":51,"context":52},"mitre_attack","T1548.004","Abuse Elevation Control Mechanism - Use of sudo or setuid binary privilege escalation"]