A Nine-Year-Old ptrace Bug Let Unprivileged Users Read SSH Keys and Shadow Passwords
CVE-2026-46333, disclosed by Qualys on May 21, exploits a race condition in the Linux kernel's ptrace access check to steal SSH host private keys, shadow password hashes, and in two variants, execute arbitrary commands as root. The bug has been in the kernel since November 2016.
On May 21, 2026, Qualys Threat Research Unit published the full advisory for CVE-2026-46333 — a logic flaw in the Linux kernel's __ptrace_may_access() function that has been present since November 2016. The vulnerability allows an unprivileged local user to steal SSH host private keys, read the shadow password database, or in two exploit variants, execute arbitrary commands as root. Qualys published four working proof-of-concept exploits alongside the advisory. An independent exploit derived from the public kernel commit appeared before the advisory was released.
The kernel patch — commit 31e62c2ebbfd, titled "ptrace: slightly saner get_dumpable() logic" — was committed publicly on May 14, a week before the full advisory. Patches are available for Debian, Fedora, and Ubuntu. The CVSS 3.1 score is 5.5 (Medium), reflecting the local-only attack vector — not the severity of what a successful exploit delivers.
The Bug
__ptrace_may_access() is the kernel function that decides whether one process is allowed to attach to and inspect another. It answers that question by reading the target process's current credentials — effective user ID, saved set-user ID, supplementary groups — and checking against the calling process's privileges.
The flaw is in the timing. When a privileged process exits, there is a narrow window between the moment its memory descriptor is detached and the moment its file descriptor table is closed. During that window, the kernel's ptrace access check skips its dumpable safeguard because the task's memory descriptor is already NULL — but the file descriptors are still open. An unprivileged process can call pidfd_getfd(2) — the file descriptor cloning interface introduced in Linux 5.6 — and copy those open descriptors out of the exiting privileged process before they close.
The targets are setuid binaries that legitimately open root-owned files during their normal exit path. No special configuration on the privileged side is required. The race triggers on normal, unmodified binary exit.
Four Exploits
Qualys developed four working exploits against four different targets, each using the same primitive:
ssh-keysign — A setuid binary that ships with every OpenSSH installation. During its brief lifetime, it opens the SSH host private key files to sign authentication challenges. The exploit races against its exit and steals open handles to /etc/ssh/ssh_host_ecdsa_key, ssh_host_ed25519_key, and ssh_host_rsa_key. Tested on default installs of Debian 13, Ubuntu 24.04, and Ubuntu 26.04.
chage — A setuid binary for managing password aging. It opens /etc/shadow during its exit path. The exploit steals the open handle and reads every local user's password hash. Tested on the same default installs.
pkexec — The PolicyKit binary. This variant executes arbitrary commands as root. Tested on default installs of Debian 13, Ubuntu Desktop 24.04 and 26.04, and Fedora Workstation 43 and 44. Requires an allow_active session at the console, meaning the attacker can be remotely logged in via SSH provided an active local console session exists.
accounts-daemon — A root daemon in the accountsservice package. Executes arbitrary commands as root with no console session requirement. Unlike pkexec, which is a setuid binary that consults PolicyKit's session authentication rules before executing, accounts-daemon is a persistent root daemon — it does not gate execution on session state, so the exploit works regardless of whether an active console session exists. Tested on default installs of Debian 13, Fedora Workstation 43 and 44.
Qualys noted that these four targets were drawn from prior research rather than an exhaustive sweep. Other setuid, setgid, file-capability binaries, and root daemons may be exploitable through the same primitive.
Nine Years
The vulnerable code path was introduced in November 2016 with Linux kernel 4.8. It traversed nearly a decade of kernel releases — across every major enterprise Linux distribution — without detection. The race window is narrow; it occurs only during process exit and requires a specific combination of a NULL memory descriptor and still-open file descriptors: a transient state that no static analysis tool or code reviewer would naturally identify as a security boundary. The fix modifies __ptrace_may_access() to cache the last user-dumpable state for tasks that no longer have a memory descriptor, and to require proper CAP_SYS_PTRACE authority where the existing check could be bypassed.
This is the fourth Linux kernel security issue requiring attention in three weeks. Copy Fail (CVE-2026-31431) was disclosed April 29. Dirty Frag (CVE-2026-43284/43500) followed on May 7. Fragnesia (CVE-2026-46300) arrived May 13. CVE-2026-46333 was disclosed May 21. Each requires a separate patch.
Patch and Mitigation
The upstream kernel fix is available. Distribution patches are available now for Debian, Fedora, and Ubuntu — patching requires a reboot.
If an immediate kernel update is not possible, the effective mitigation is setting kernel.yama.ptrace_scope=3 via sysctl, which restricts ptrace to processes with CAP_SYS_PTRACE. This blocks the exploit primitive entirely. Setting the value to 0 disables Yama ptrace restrictions entirely and should not be used as a workaround.
The CVSS Medium score warrants a note. It reflects the local attack vector — an attacker must already have a shell on the system. That prerequisite is real but routinely met: web application exploitation, phishing-delivered malware, compromised CI jobs, stolen developer credentials, and shared-hosting abuse all produce local footholds. Any of those entry points on an unpatched system running the affected binaries converts immediately to SSH key theft, shadow database access, or root execution depending on which exploit variant applies.
Patch and reboot. The four exploits are public, the primitive is documented, and the affected binaries are present on default installs of the three most widely deployed Linux distributions.