ssh-keysign-pwn: Reading Root-Owned Files via a ptrace Logic Bug
ssh-keysign-pwn: A six-year-old logic bug in the kernel’s
__ptrace_may_access()function, reported by Qualys and patched by Linus Torvalds on May 14, 2026. Unprivileged users can read root-owned files including SSH host private keys and/etc/shadow. All pre-31e62c2ebbfdkernels affected.
Another One
May 2026 has not been kind to the Linux kernel. Dirty Frag, Fragnesia, and now—ssh-keysign-pwn—disclosed by Qualys on May 14 and fixed by Linus Torvalds the same day.
This one is different from the “copy something into page cache” family. It’s a pure logic bug in __ptrace_may_access(), the kernel function that decides whether one process can inspect another.
| Metric | Value |
|---|---|
| Reported by | Qualys Security Advisory |
| Fixed by | Linus Torvalds |
| Fix commit | 31e62c2ebbfd |
| Lurked for | ~6 years |
| First flagged by | Jann Horn (Google), October 2020 |
| PoC published by | _SiCk |
| Impact | Read root-owned files as unprivileged user |
| Exploit complexity | 100–2000 spawns per successful steal |
How It Works
The bug lives in __ptrace_may_access(). This function is the gatekeeper for process introspection — it checks whether a process is allowed to poke around in another process’s state.
There’s a special case: when task->mm == NULL (the target process has no memory descriptor — happens when a thread is exiting, or for kernel threads), the function skips the dumpable check entirely.
Here’s the code path that makes this exploitable:
- A process calls
do_exit()to terminate do_exit()runsexit_mm()first — this tears down the memory descriptor (mm)- Then it runs
exit_files()— but the file descriptors are still alive at this point - With
task->mm == NULLbut file descriptors still open,pidfd_getfd(2)can steal those fds if the caller’s uid matches
Normally, ptrace access checks would block a less-privileged process from reaching into a root process’s open file handles. But the mm == NULL bypass knocks out the dumpable check, and pidfd_getfd(2) does the rest.
This is a textbook TOCTOU race, but the window is wide enough that the PoC hits in 100–2000 attempts.
Exploit Targets
Two tools were published:
sshkeysign_pwn — targets ssh-keysign, a helper binary that signs host authentication challenges. The binary opens SSH host key files (/etc/ssh/ssh_host_{ecdsa,ed25519,rsa}_key, mode 0600) before calling permanently_set_uid() to drop privileges. Then it checks whether EnableSSHKeysign is set in sshd_config — if not, it bails out with the key fds still open. This design has been in OpenSSH since 2002.
chage_pwn — targets chage -l <user>. The binary opens /etc/shadow via spw_open(O_RDONLY), then calls setreuid(ruid, ruid) — dropping all privileges since both arguments are the real uid. In the race window between the privilege drop and the file close, the fd is stealable.
Timeline
| Date | Event |
|---|---|
| ~2020 | Jann Horn identifies the FD-theft pattern and proposes a patch (not merged) |
| 2026-05-14 | Qualys reports the vulnerability; Linus Torvalds commits the fix (31e62c2ebbfd) |
| 2026-05-14 | Brad Spengler (@spendergrsec) publishes analysis |
| 2026-05-14 | _SiCk publishes PoC exploits on GitHub |
| 2026-05-15 | Qualys sends disclosure to oss-security |
The gap from Jann Horn’s 2020 patch proposal to Qualys’s 2026 report is notable. The fix had been drafted five years ago but never made it upstream.
The Fix
Linus committed the fix as commit 31e62c2ebbfd. His commit message noted:
“we have one odd special case: ptrace_may_access() uses ‘dumpable’ to check various other things entirely independently of the MM (typically explicitly using flags like
PTRACE_MODE_READ_FSCREDS), including for threads that no longer have a VM (and maybe never did, like most kernel threads). It’s not what this flag was designed for, but it is what it is.”
The patch adjusts ptrace behavior to properly handle the mm == NULL case. It effectively closes the bypass window.
Check Your Kernel
# Check if your kernel has the fix
uname -r
# Fixed kernels have commit 31e62c2ebbfd included
# All kernels before 2026-05-14 are vulnerable
What Makes This One Interesting
Three things stand out:
-
It was fixed the same day it was reported. Linus turned this around in hours. That’s unusually fast for a kernel fix, suggesting the patch was straightforward once the bug was understood.
-
Jann Horn found this in 2020. The community had a patch proposal sitting in the mailing list archives for five years. The FD-theft shape was known, but nobody pushed it through.
-
The targets are ancient.
ssh-keysign’s fd-leaving pattern dates to 2002.chage’sspw_open+setreuidsequence is similarly long-standing. This isn’t a bug in SSH or shadow-utils — it’s a kernel bug that weaponizes existing fd-handling patterns in privileged binaries.
This is also the third major Linux kernel vulnerability in May 2026, following Copy Fail and Dirty Frag. The pace of disclosure is accelerating — partly because AI-assisted auditing tools are finding old bugs faster, and partly because the disclosure ecosystem is fragmenting (embargoes being broken, PoCs released before patches).
References
- Kernel fix commit: 31e62c2ebbfd
- Phoronix report: Linux’s Latest Vulnerability Allows Reading Root-Owned Files By Unprivileged Users
- GitHub PoC: 0xdeadbeefnetwork/ssh-keysign-pwn
- 9to5Linux: Six-Year-Old Linux Kernel Flaw Lets Unprivileged Users Read Root-Owned Files
- Qualys oss-security post: Logic bug in __ptrace_may_access()
- Jann Horn’s 2020 patch: lore.kernel.org