ctipilot.ch

Home · Live brief · Daily brief 2026-05-23

CVE-2026-46333 ssh-keysign-pwn: a 9-year ptrace race in the Linux kernel reaching root and SSH host keys

notable vulnerability discovered 2026-05-23 05:00 UTC deep dive

Part of run 2026-05-23-852c21c8 (intel · Claude Opus 4.7)

Background. The Linux kernel's __ptrace_may_access() permission check in kernel/ptrace.c has been a recurring source of local-privilege-escalation primitives ever since the dumpable / capability model was introduced. CVE-2019-13272 (Jann Horn, 2019) exploited a similar credential-window confusion in the same function. The introduction of pidfd_getfd() in v5.6-rc1 (January 2020) added a second axis — fd duplication across processes — that has compounded ptrace-window primitives by allowing fds harvested during a privileged credential window to be reused under the attacker's UID. Qualys's Looney Tunables (CVE-2023-4911) set the template for the credibility-with-public-exploits disclosure pattern Qualys has continued since. CVE-2026-46333 fits squarely in that lineage: a long-dormant logic error reaching first-class root primitives, with the disclosure structured around defender-actionable analysis rather than weaponisation help.

The bug. Qualys TRU disclosed CVE-2026-46333 on 2026-05-20 (the URL path encodes the disclosure date; the Qualys blog also carries a 2026-05-22 rendered "Date" field that appears to reflect a content update; the brief uses the URL-encoded disclosure date as anchor) (The Hacker News, 2026-05-21 · Canonical / Ubuntu, 2026-05-19; upstream kernel fix landed 2026-05-14) — a TOCTOU race in __ptrace_may_access() present since Linux v4.10-rc1 (November 2016). The window is the brief interval when a privileged process drops credentials — for example a setuid binary calling setuid() to lower privilege after performing a privileged action. During that window __ptrace_may_access() incorrectly permits ptrace attachment, because credential comparison is performed against the uid/gid captured at the time of the ptrace_may_access() call rather than at the point of the actual access; the dumpable flag is re-evaluated too late. An unprivileged caller racing the credential drop wins ptrace rights on the target.

The chain. A standalone ptrace win is interesting; the chain that promotes it to a four-target root primitive is the combination with pidfd_getfd(). Once attached, the attacker uses pidfd_getfd() to duplicate file descriptors from the privileged process into the attacker's own process. Those fds — opened by the privileged process for reading /etc/shadow, writing to /etc/ssh/ssh_host_*_key, executing as root, or speaking to D-Bus / systemd over a privileged socket — are now usable under the attacker's UID. Qualys developed four working exploits, detailed in the public advisory (exploit code itself was withheld during coordinated disclosure; the advisory and PoC outputs are public):

  • chage (setuid-root, setgid-shadow) → reads /etc/shadow and recovers the local hash database for cracking.
  • ssh-keysign (setuid-root) → exfiltrates SSH host private keys from /etc/ssh/ — the host's identity to the rest of the network, enabling SSH MITM and host impersonation on internal links.
  • pkexec (setuid-root) → arbitrary root command execution; functionally equivalent to PwnKit (CVE-2021-4034) outcomes but reached through a different primitive.
  • accounts-daemon (root daemon, not setuid) → arbitrary root command execution via hijacked D-Bus connection to systemd.

Exploits confirmed working on Debian 13, Ubuntu 24.04 / 26.04, Fedora 43 / 44; the underlying primitive applies to any distro carrying a v4.10-or-newer kernel and a standard setuid surface. Prerequisites: a local unprivileged shell on the target host. No network exposure required — this is a pure post-foothold escalation primitive — and no kernel hardening short of restricting ptrace defeats it on a default Linux server.

MITRE ATT&CK mapping. Primarily T1068 Exploitation for Privilege Escalation; the SSH-key exfiltration outcome maps to T1552.004 Unsecured Credentials: Private Keys; the D-Bus path through accounts-daemon is closer to T1543.002 Create or Modify System Process: Systemd Service in outcome shape.

Detection vantage. Qualys published QID 387392 for vulnerability scanning. Behavioural detection is the operationally interesting axis because the primitive is hard to defeat without a kernel update:

  • Syscall pairing. EDR / auditd hunt for pidfd_getfd syscall paired with ptrace calls originating from a non-root process targeting a setuid-root process. The combination is rare in normal workloads and is the canonical fingerprint of the exploitation pattern.
  • Anomalous credential-file reads. /etc/shadow read by non-root, non-PAM-stack processes; /etc/ssh/ssh_host_*_key read by non-sshd processes.
  • D-Bus → systemd anomalies. accounts-daemon D-Bus connections from process trees lacking a legitimate parent (e.g. spawned from a shell rather than a login session).
  • Audit-rule pattern. auditctl -w /etc/shadow -p r -k shadow_read plus -w /etc/ssh -p r -k ssh_host_key_read; pair with -a always,exit -F arch=b64 -S pidfd_getfd -k pidfd_getfd_audit.

Hardening / mitigation. The supported mitigation hierarchy:

  1. Patch. Upstream kernel fix landed 2026-05-14; distribution vendor packages are available from Debian, Fedora, Red Hat, SUSE, AlmaLinux, CloudLinux and Ubuntu (Canonical's ssh-keysign-pwn advisory). Roll the kernel where USNs / DSAs are available; for ELRepo / longterm trees, build against the patched stable tag.
  2. Interim: sysctl kernel.yama.ptrace_scope=2. Restricts ptrace to processes carrying CAP_SYS_PTRACE. This eliminates the primitive on non-root processes but breaks debuggers and some profiling tools; deploy via configuration management with explicit allowlist of dev workstations or jump hosts where ptrace is needed.
  3. Restrict pidfd_getfd via seccomp on multi-tenant or container hosts. Where workloads can be characterised, deny pidfd_getfd via seccomp profiles on container runtimes; Docker / containerd default profiles can be extended.
  4. Container-runtime context. Multi-tenant Kubernetes nodes where lower-privilege workloads share the host kernel are the highest-risk environment because the primitive operates at kernel level — userns remapping does not block it. Treat patched-kernel rollout as a hard prerequisite for multi-tenant nodes.

Why this is a deep dive and not a § 2 entry. CVE-2026-46333 is a local LPE primitive — no pre-authentication network surface, no automated mass-exploitation pattern in the wild yet — so it does not clear the § 2 inclusion gates the prompt enforces. But the combination of all-major-distros affected, four working Qualys exploits detailed in the public advisory, nine-year dormancy in a kernel function under repeated scrutiny, and SSH host-key exfiltration as one of the achievable outcomes makes it the highest-signal Linux-LPE deep dive of the last fortnight. Every EU/CH public-sector environment running Linux containers, multi-tenant compute or developer workstations sits within the affected surface; the patch rollout window is the actionable defensive frame.

Action items

  • Roll kernel patches for CVE-2026-46333 on every Linux estate; raise kernel.yama.ptrace_scope=2 as interim on hosts that cannot be rebooted yet. Four working Qualys exploits detailed in the public advisory (exploit code withheld during coordinated disclosure), all major distros affected, SSH host-key exfiltration in the outcome set. Multi-tenant Kubernetes nodes carry highest residual risk. Full detection / hardening package in § 5 Deep Dive below.
vulnerabilities lpe priv-esc poc-public patch-available global CVE-2026-46333