Your server has an unprivileged user on it. Maybe a developer with a restricted shell, a compromised service account, a container escape — it doesn’t matter. With CVE-2026-46333, that may be enough. On affected default configurations, they can expose your SSH host private keys and your entire shadow password database. No memory corruption. No shellcode. Just a nine-year-old logic flaw that nobody noticed.

TL;DR

  • CVE-2026-46333 (codename: ssh-keysign-pwn) is a race condition in the Linux kernel’s __ptrace_may_access() function, present since November 2016 (kernel v4.10-rc1)
  • Any unprivileged local user can reliably steal SSH host private keys and dump /etc/shadow
  • Root command execution is also possible, but depends on the target binary and system configuration
  • Working public proof-of-concept is available — patch immediately and reboot (installing the update without rebooting leaves the vulnerable kernel running)
  • Interim workaround: kernel.yama.ptrace_scope=2 via sysctl
  • If untrusted users had local access to the system, rotate your SSH host keys

Why This Matters

SSH host keys are the root-of-trust for your infrastructure. They prove to connecting clients that they’re talking to the right server — not an impostor. If an attacker steals them, they can impersonate your servers silently and intercept connections without triggering any alerts. There’s no certificate revocation mechanism, no expiry date. The only fix is rotating every key.

The /etc/shadow file stores hashed passwords for every local account on the system. With it, an attacker can crack passwords offline — at GPU speed, with no rate limiting, no lockout, no logs — and reuse those credentials across your environment.

On affected default configurations, CVE-2026-46333 can expose both of these to an unprivileged attacker with local shell access.


Nine Years in Plain Sight

The flaw lives in __ptrace_may_access(), a function in the Linux kernel that decides whether one process is allowed to inspect another. ptrace is the system call behind debuggers like gdb and tracers like strace — powerful tools that need tight access controls.

The bug was introduced in kernel v4.10-rc1 in November 2016. Since then, every Linux system running a kernel from that point onward has been carrying this flaw — undetected through countless security audits, fuzzing campaigns, and kernel releases.

The logic error is subtle. When a privileged process (running as root) begins dropping its credentials — transitioning to an unprivileged state — there is a brief window where the kernel’s access check gives the wrong answer. The process has already started dropping privileges, but __ptrace_may_access() still considers it reachable via ptrace-family operations. The dumpable flag, which is supposed to block this path, doesn’t close the window fast enough.

Alone, this race condition is hard to exploit reliably. But in kernel v5.6-rc1 (January 2020), Linux gained the pidfd_getfd() system call — a feature that lets you duplicate a file descriptor from another process by its PID file descriptor. Combined with the ptrace window, this becomes a precise and reliable attack primitive.

The vulnerability was discovered by Qualys researchers, privately reported to the Linux kernel security team on May 11, 2026, and patched on May 14. Distributions began shipping fixes and the public disclosure date was May 15, 2026. Qualys published their full technical advisory on May 20, 2026.


How the Exploit Works

Think of it like pickpocketing someone who is in the middle of handing their wallet to a guard. For a split second, neither person has full control of it. The attacker grabs it in that window.

Here’s the sequence:

  1. Find a target binary — identify a set-uid-root binary or root-owned process that opens a sensitive file during its normal execution
  2. Race the credential drop — trigger the binary and race to hit the __ptrace_may_access() check during the credential-dropping window
  3. Call pidfd_getfd() — once the window is open, duplicate the file descriptor the privileged process has open (e.g., the SSH private key file)
  4. Read the file — the duplicated descriptor is now held by the attacker’s unprivileged process, but still carries the read permissions of the original privileged opener

The attacker never needs to corrupt memory or execute shellcode — they simply borrow an already-open file descriptor at the exact moment the kernel’s access check is confused.

Terminal window
# Conceptual PoC flow (not a working exploit)
# 1. Launch target SUID binary in background
/usr/lib/openssh/ssh-keysign &
TARGET_PID=$!
# 2. Open a pidfd for the target process
# 3. Race: call pidfd_getfd() during the credential-drop window
# 4. Read the stolen descriptor — now accessible as unprivileged user
cat /proc/self/fd/$STOLEN_FD # outputs /etc/ssh/ssh_host_ed25519_key

The proof-of-concept — published on GitHub as ssh-keysign-pwn — demonstrates this reliably on modern Linux distributions.


Confirmed Attack Paths

Qualys identified four targets across two categories:

Credential disclosure (reliable on all tested systems):

BinaryTypeWhat it exposes
ssh-keysignSUID root binary/etc/ssh/*_key — SSH host private keys
chageSUID/SGID binary/etc/shadow — hashed passwords for all accounts

Root command execution (configuration-dependent):

TargetTypeCondition
pkexecSUID root binaryRequires an allow_active PolicyKit session at the local console
accounts-daemonRoot-owned daemonExploits a DBus channel to AccountsService; tested on Debian 13 and Fedora Workstation

The credential disclosure paths work broadly across affected distributions. The root execution paths are real but depend on what’s running — pkexec requires physical console access with an active session, and accounts-daemon is typically present on desktop/workstation installs, not headless servers.

ssh-keysign is particularly notable because it’s the only SUID binary shipped by OpenSSH. Its entire purpose is to read SSH host keys during host-based authentication — a narrow, supposedly safe operation. This flaw turns it into a reliable credential exfiltration vector.


Who Is Affected

Any kernel from v4.10-rc1 (November 2016) onward carries the race condition. The pidfd_getfd() syscall (added in v5.6, January 2020) is required for the reliable exploit primitive, but the underlying flaw predates it.

Confirmed vulnerable distributions with patches issued:

  • Ubuntu — all currently supported releases (20.04 LTS through 26.04 LTS); 14.04 and 16.04 are covered under Extended Security Maintenance (ESM/Legacy), not standard support
  • Debian 13
  • Fedora 43, 44
  • Red Hat Enterprise Linux and derivatives (AlmaLinux, CloudLinux)
  • SUSE Linux Enterprise

This is the fourth critical Linux kernel vulnerability in three weeks, following Dirty Frag, Copy Fail, and Fragnesia. If you’ve been deferring kernel updates, the debt is compounding.


CVSS and Severity Context

The scoring picture is fragmented. The kernel.org CNA assigned a CVSS 3.1 score of 7.1 (High). CISA’s ADP enrichment listed 5.5 (Medium). NVD’s own analysis was still marked N/A at the time of writing. Ubuntu’s security team assigned an internal priority of High despite the lower CVSS figures, noting that the impact — disclosure of sensitive credentials to unprivileged local users — warrants elevated treatment.

The “local access required” attribute is what mechanically pulls CVSS scores down. In practice, local access is common: shared hosting environments, multi-tenant servers, CI/CD runners, container escapes from adjacent workloads, and insider threats all qualify. If your system fits any of those categories, treat this as high severity regardless of which score you see.


Detection

The exploit is local and fast, but it does leave syscall traces. The most reliable signal is pidfd_getfd called by an unprivileged user against a SUID process — this is abnormal in normal system operation.

Audit rules:

/etc/audit/rules.d/cve-2026-46333.rules
-a always,exit -F arch=b64 -S pidfd_getfd -k pidfd_getfd_suspicious
-a always,exit -F arch=b64 -S ptrace -F a0=0x10 -k ptrace_attach

Sigma rule concept:

title: Suspicious pidfd_getfd from Unprivileged User
detection:
selection:
syscall: pidfd_getfd
uid: '>= 1000'
condition: selection

Behavioral indicators to watch:

  • ssh-keysign executed outside of an active SSH session context
  • chage invoked by a non-root user with anomalous timing
  • /proc/<pid>/fd directory traversal on a SUID process from a different UID
  • File descriptor activity on /etc/ssh/*_key paths from non-root processes

A note on file access monitoring: using atime changes on SSH host key files is not reliable for detecting exploitation. Many systems mount with relatime or noatime, and legitimate sshd activity reads these files regularly anyway. Syscall-level auditing via auditd or eBPF-based tooling gives a much cleaner signal.


What You Can Do Now

1. Patch and reboot

Install the kernel update from your distribution and reboot. Updating the package without rebooting leaves the vulnerable kernel in memory — you are not protected until the new kernel is running.

Terminal window
# Debian/Ubuntu
sudo apt update && sudo apt upgrade linux-image-generic
sudo reboot
# RHEL/Fedora
sudo dnf update kernel
sudo reboot
# Arch/CachyOS
sudo pacman -Syu
sudo reboot

2. Apply the interim workaround if you can’t reboot immediately

Terminal window
# Restrict ptrace to processes with CAP_SYS_PTRACE only
echo kernel.yama.ptrace_scope=2 | sudo tee /etc/sysctl.d/99-CVE-2026-46333.conf
sudo sysctl -p /etc/sysctl.d/99-CVE-2026-46333.conf

Side effect: this breaks unprivileged use of gdb, strace, and similar tools. Acceptable for production servers; disruptive on developer workstations.

3. Rotate SSH host keys if exposure is plausible

If untrusted users have had local shell access to any of your systems — even briefly — assume the SSH host keys may have been stolen. You cannot verify whether the exploit was used:

Terminal window
# Remove old host keys and generate new ones
sudo rm /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart ssh

After rotating, clients will see a host key mismatch warning. Do not instruct users to blindly accept the new key or run ssh-keyscan without first verifying the new fingerprint out-of-band — if a MITM situation exists, blindly trusting the presented key defeats the purpose of rotating. Distribute the new fingerprint through a trusted channel (configuration management, internal documentation, a verified Slack message) and have users confirm it matches before accepting.

Terminal window
# Get the new fingerprint to distribute
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

4. Verify your running kernel version

Terminal window
uname -r
# Compare against your distro's patched version in the security advisory

5. Check if ssh-keysign is installed and SUID

Terminal window
ls -la /usr/lib/openssh/ssh-keysign 2>/dev/null \
|| ls -la /usr/libexec/openssh/ssh-keysign 2>/dev/null

If the binary exists with the SUID bit set and you haven’t rebooted into a patched kernel, you’re exposed.


The kernel.org CNA called this a 7.1. CISA said 5.5. Ubuntu said High. What all three agree on is that an unprivileged shell is enough to walk out with your SSH host keys. Nine years is a long time for a bug to hide in one of the world’s most audited codebases. Patch tonight, rotate your keys if there’s any doubt, and if this is the fourth kernel patch you’ve applied this month — it might be time to revisit your update cadence.



Sources