Summary
SSHole is an authentication bypass in OpenSSH's sshd before 10.6p2 on Linux systems using musl libc without PAM. Sending a password between 257–1024 bytes causes musl's crypt() to return * — the same sentinel value stored for accounts with no password — causing sshd to accept the login. Affects Alpine Linux in its default configuration. Active exploitation confirmed on a honeypot less than 9 hours after disclosure.
Affected Asset
OpenSSH sshd before 10.6p2, compiled against musl libc without PAM — primarily Alpine Linux (all branches before the Nov 5 2026 patches), OpenWrt, Buildroot, Yocto, and Alpine-based Docker images. glibc distros (Debian, Ubuntu, RHEL, Fedora) are not affected.
Affected Endpoint
OpenSSH sshd password authentication path — specifically the interaction between auth-passwd.c's call to crypt() and musl libc's crypt_sha512.c overlong-key handling.
Prerequisites
sshdlinked against musl libc (Alpine, OpenWrt, Buildroot, Yocto, or Alpine Docker base images)- OpenSSH < 10.6p2 — unpatched
openssh-server - PAM disabled — Alpine's default
openssh-serverpackage ships without PAM; also any configuration withUsePAM no - Password authentication enabled (
PasswordAuthentication yesis the default) - At least one account with
*as the shadow password field (key-only users, root on Alpine ≥ 3.16, defaultalpineuser on AWS/Azure cloud images) - At least one other account with a real password hash (needed for
sshd's fake-salt timing path to reference)
Steps to Reproduce
- Identify a target Alpine host with password authentication open to the network
- Target an account that uses
*as its shadow entry — commonlyrooton Alpine ≥ 3.16, or any key-only deploy user - Send an SSH login with a password between 257 and 1024 bytes (any content, any printable characters)
- musl's
crypt()returns*due to the 256-byte cap;sshdcompares*with the stored*— they match — login succeeds - On Alpine's default AWS/Azure images the
alpineuser has passwordlessdoas, so this yields an effective root shell
# Minimal proof of concept (Python)
import subprocess, "A" * 300
password = "A" * 300 # any payload > 256 bytes works
subprocess.run(["ssh", "-o", "PasswordAuthentication=yes",
"root@<alpine-host>"], input=password.encode())
Evidence
- Disclosed 5 November 2026 by researcher Özgün Kültekin (Wakefield) at sshhole.com
- MITRE CVE-2026-123158 published same day; CVSS 3.1 score 8.1
- Threat intelligence firm Previdian confirmed root access on an Alpine honeypot within 9 hours of disclosure
- Public PoC available at github.com/oz9un/sshole
- CISA rates exploitation as proof-of-concept; not yet in KEV catalog as of post date
Impact
An unauthenticated attacker with network access to SSH can log into any account whose /etc/shadow entry is * — without credentials, without keys, without prior access. On Alpine's official cloud images this is effectively unauthenticated root via the default alpine user. Any service, container, or VPS built on an Alpine base image running the default openssh-server package is in scope.
Root Cause — How the Bug Works
Three independent design decisions from across a decade of different projects collide to create this bug:
Accounts that should never accept passwords store * in their password field. No real hash can produce *, so it is a safe sentinel.
musl changes crypt() so that on failure it returns * instead of NULL (to avoid crashes in programs that don't check for NULL). Three weeks later, musl's SHA-512 crypt implementation caps passwords at 256 bytes to prevent DoS; anything longer triggers an early return — which also returns *.
To prevent user-enumeration via timing (CVE-2016-6210), sshd borrows another account's salt to hash the supplied password even for accounts that don't exist or have no real hash. The comparison then runs between the result of crypt(oversized_pw) — which returns * — and the stored * sentinel. They match.
To allow SSH key logins without PAM, Alpine switches root's shadow entry from ! to *. This unknowingly moves root into the vulnerable class. The default alpine user on AWS and Azure images follows the same pattern.
Özgün Kültekin finds the bypass while fuzzing sshd across different libc and PAM combinations. The bug has been silently exploitable since at least 2016.
Am I Affected? — Quick Check
- Running Alpine Linux with the default
openssh-serverpackage? Yes. - Running an Alpine-based Docker image that installs and runs
sshd? Likely yes. - Running OpenWrt, Buildroot or Yocto with sshd and no PAM? Check your musl version and openssh version.
- Running Debian, Ubuntu, RHEL, or any glibc distro? Not affected.
- Running OpenBSD? Not affected.
- Using Dropbear instead of OpenSSH? Not affected.
- Using PAM (
UsePAM yes)? Not affected.
Check your shadow file for star entries: grep ':\*:' /etc/shadow. Any account listed there is in scope if the other conditions are met.
Remediation
Primary fix — update OpenSSH:
# On Alpine
apk update && apk upgrade openssh
# Verify the patched version is installed
ssh -V # should show OpenSSH_10.6p2 or later
rc-service sshd restart
Interim mitigation — disable password authentication:
echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/00-no-passwords.conf
rc-service sshd restart
Either fix independently closes the attack path. If you manage Alpine Docker images, rebuild them on the patched openssh-server package. Cloud images (Alpine on AWS / Azure) should be patched or replaced.
Verification Steps
- Confirm fixed version:
apk info openssh-server | grep openssh— expect10.6p2-r0or later - Confirm password auth is off or confirm the patch:
sshd -T | grep passwordauthentication - Check for signs of exploitation — look for successful logins to key-only accounts in
/var/log/auth.logor/var/log/messages - Run the detection script:
bash <(curl -s https://raw.githubusercontent.com/oz9un/sshole/main/check.sh) - Review
lastandlastboutput for unexpected successful logins, especially for root or deploy users
References
- sshhole.com — original researcher write-up by Özgün Kültekin
- github.com/oz9un/sshole — detection script and PoC
- NIST NVD — CVE-2026-123158
- OpenSSH release notes — 10.6p2
- The Hacker News — Active exploitation confirmed within 9 hours
- SecurityWeek — OpenSSH emergency patch coverage
- Safe Security — Full technical breakdown