Patching is step one. But if your server ran an unpatched kernel with local users — even unprivileged ones — you have a second problem: you don't know whether someone already used that window.
This guide covers the full response: patch, mitigate if you can't patch yet, rotate your SSH host keys, and check whether you were hit.
What the Vulnerability Does
CVE-2026-46333, nicknamed "ssh-keysign-pwn," exploits a race condition in the Linux kernel's process exit path. The flaw lives in __ptrace_may_access().
Here's the sequence. When a privileged process exits, the kernel calls exit_mm() before exit_files(). That ordering creates a brief window: the process has released its memory descriptor (set to NULL), but its file descriptors are still open. Because __ptrace_may_access() skips its dumpable check when the target task's mm is NULL, an unprivileged attacker can call pidfd_getfd(2) during that window and clone a file descriptor out of the dying process.
This is a classic TOCTOU race. The public proof-of-concept — released hours after the upstream kernel fix on May 14 — reliably hits in 100 to 2,000 attempts. On a modern CPU, that takes seconds.
The two primary targets are SUID binaries that legitimately open root-owned files during their exit path:
ssh-keysign— opens/etc/ssh/ssh_host_*_key(your SSH host private keys)chage— opens/etc/shadow(your hashed user passwords)
An attacker who steals a host key can impersonate your server in future connections. An attacker who reads /etc/shadow can crack passwords offline.
The bug was introduced with pidfd_getfd(2) in Linux 5.6 (2020). Upstream fix: commit 31e62c2ebbfd, merged May 14, 2026.
Step 1 — Patch First
Check your running kernel:
uname -rPatched kernel versions by distribution:
| Distribution | Patched version |
|---|---|
| AlmaLinux 8 | kernel-4.18.0-553.124.4.el8_10 |
| AlmaLinux 9 | kernel-5.14.0-611.54.6.el9_7 |
| AlmaLinux 10 | kernel-6.12.0-124.56.5.el10_1 |
| CloudLinux 8 | kernel-4.18.0-553.124.4.lve.el8 |
| CloudLinux 9 | kernel-5.14.0-611.54.6.el9_7 |
| CloudLinux 10 | kernel-6.12.0-124.56.5.el10_1 |
Upstream stable patched versions include 6.12.89, 6.6.139, 6.1.173, 5.15.207, and 5.10.256.
AlmaLinux / RHEL / CloudLinux:
sudo dnf clean metadata && sudo dnf upgrade && sudo rebootDebian / Ubuntu — check your vendor's advisory for the exact patched package version for your release.
AlmaLinux 8 (kernel 4.18) has the underlying logic bug but is not exploitable with current public PoCs. Patch it anyway. CloudLinux 7 (kernel 3.10) predates the regression and is not affected.
Step 2 — Mitigate if You Can't Patch Immediately
If an immediate reboot is not possible, tighten Yama's ptrace scope. Setting ptrace_scope to 3 blocks pidfd_getfd access checks for non-privileged processes and stops the known exploit path.
sudo sysctl -w kernel.yama.ptrace_scope=3
echo 'kernel.yama.ptrace_scope = 3' | sudo tee /etc/sysctl.d/99-cve-2026-46333.conf
sudo sysctl --systemWhat you lose: unprivileged users can no longer attach gdb, strace, or perf trace to their own processes. If that's acceptable in your environment, this is a reliable buy-time control.
Alternative: remove SUID bits from the targets
sudo chmod u-s /usr/libexec/openssh/ssh-keysign
sudo chmod u-s /usr/bin/chageThis removes the attack surface entirely but also breaks host-based authentication (ssh-keysign requires SUID to function) and password expiry management for non-root users. Evaluate the trade-off before applying in production.
Also consider hidepid on /proc to limit what unprivileged users can see about other processes:
sudo mount -o remount,hidepid=2 /procAdd to /etc/fstab to persist across reboots:
proc /proc proc defaults,hidepid=2 0 0
hidepid=2 means users can only see their own processes in /proc. It does not block the exploit directly, but it raises the cost of reconnaissance.
Step 3 — Rotate Your SSH Host Keys
If your server ran an unpatched kernel with local users, treat your SSH host keys as compromised. Rotation takes two minutes. Client disruption is manageable.
Generate new host keys:
sudo rm /etc/ssh/ssh_host_*_key /etc/ssh/ssh_host_*_key.pub
sudo ssh-keygen -A
sudo systemctl restart sshdssh-keygen -A regenerates all missing host key types (RSA, ECDSA, Ed25519) with default parameters.
Check the new fingerprints:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
sudo ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pubHandle client-side trust. When clients reconnect they will see a host key warning — that's expected and correct. Have them remove the old entry:
ssh-keygen -R <your-server-hostname-or-ip>Or remove the specific line from ~/.ssh/known_hosts manually. If you manage hosts centrally (Ansible, Puppet, SSHFP DNS records), update those stores now.
Step 4 — Check if You Were Hit
The public PoC requires hundreds to thousands of rapid ssh-keysign or chage process spawns. That pattern leaves traces.
Check auth.log for abnormal ssh-keysign activity:
grep ssh-keysign /var/log/auth.log | awk '{print $1,$2}' | sort | uniq -c | sort -rn | head -20A normal host has a handful of ssh-keysign entries tied to actual SSH connections. If you see hundreds or thousands of entries in a short window, that is the exploit loop.
If you run auditd, search for pidfd_getfd syscall activity:
ausearch -sc pidfd_getfd --start recentFor broader historical review:
ausearch -sc pidfd_getfd -ts 2026-05-01 -te 2026-05-17No results means either the syscall was never invoked by non-privileged processes, or auditd was not watching it. Add the rule going forward:
sudo auditctl -a always,exit -F arch=b64 -S pidfd_getfd \
-F auid>=1000 -F auid!=4294967295 -k pidfd_getfd_watchCheck /etc/shadow access timestamps (modification time alone is insufficient — the exploit reads without writing):
sudo stat /etc/shadow
sudo ls -lu /etc/shadow # -u shows access timeAn unexpected recent access time is a signal, not proof. Shadow passwords have many legitimate readers.
If you have eBPF tooling available:
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_pidfd_getfd { printf("%s[%d]\n", comm, pid); }'This shows any process invoking pidfd_getfd in real time. Run this on an unpatched system as a detection layer while you schedule the maintenance window.
Checklist
- Checked running kernel version with
uname -r - Applied vendor patch and rebooted
- Or applied
ptrace_scope=3sysctl as temporary mitigation - Rotated SSH host keys with
ssh-keygen -A - Restarted
sshdafter key rotation - Notified users / automation to accept new host key fingerprints
- Grepped
auth.logfor abnormalssh-keysignvolume - Ran
ausearchforpidfd_getfdactivity (if auditd is running) - Added
auditctlrule to watchpidfd_getfdgoing forward - Reviewed SSHFP DNS records or central known_hosts stores if applicable
Patching closes the hole. Key rotation removes the value of anything that may have been taken. The audit step tells you whether you're doing post-incident cleanup or just hardening.
If your review of auth.log shows clear exploitation signs, treat this as a full incident: assume /etc/shadow was read, reset passwords for all local accounts, and review what else was accessible from those compromised credentials.