Threat Advisory

sshhole: OpenSSH on musl Linux Accepts Arbitrary Long Passwords for Locked Accounts

TLT
Threat Landscape Team
2026-11-057 min read

OpenSSH built against musl libc and running without PAM accepts any password between 257 and 1024 characters for accounts whose password field in /etc/shadow is exactly *. The accounts affected are those intentionally locked or configured for key-only authentication, including root on many Alpine cloud images, deploy users, and certain LDAP-mapped accounts.

The condition is present only on musl-based systems that do not use PAM for password verification. glibc systems, systems with UsePAM yes, Dropbear, and OpenBSD are unaffected. OpenSSH 10.6p2, released 5 November 2026, contains a workaround. Alpine has backported the fix across supported and several EOL branches.

Affected Configurations

A system is vulnerable only when all of the following are true:

  • OpenSSH linked against musl libc (Alpine Linux, OpenWrt in certain builds, Buildroot, Yocto, and a large fraction of Docker images).
  • UsePAM is disabled (the default for the OpenSSH package on Alpine).
  • Password authentication is enabled (PasswordAuthentication yes, the upstream default).
  • At least one local account has the password field set to *.
  • At least one other local account has a real crypt hash ($5$, $6$, or equivalent) that can supply a salt.

When these conditions align, any password of length 257–1024 bytes is accepted for the * account. Shorter passwords and passwords longer than 1024 bytes are rejected.

Technical Mechanism

musl’s crypt() has returned the literal string "*" on failure since commit b3c4cc12 (August 2012) instead of the POSIX-required NULL. Separately, musl’s SHA-512 crypt implementation (commit 88bf5a8a, also August 2012) rejects passwords longer than 256 bytes and returns "*".

OpenSSH’s non-PAM password verification path, after the CVE-2016-6210 timing-attack mitigation, obtains a salt from another real account via pick_salt() and calls crypt(password, salt). When the supplied password exceeds 256 bytes:

  1. musl’s crypt() fails and returns "*".
  2. OpenSSH compares the returned value against the stored field.
  3. For an account whose stored field is also "*", the comparison succeeds.

The interaction is deterministic. The researcher who published the detailed analysis on sshhole.com tested approximately 17,600 authentication attempts across twelve different builds; only the musl + no-PAM combination accepted the long passwords.

The same * token has been used for decades to indicate a locked or passwordless account. The combination of musl’s failure return value, the 256-byte password length limit, and OpenSSH’s salt-borrowing logic for constant-time comparison produced a collision that went untested for years.

Impact and Attack Surface

Successful authentication grants a full login session as the target account. On typical Alpine cloud images the affected account is root, with * in /etc/shadow and public-key authentication expected. Many container images, CI runners, embedded devices, and edge systems based on Alpine, Buildroot, or Yocto share the same pattern: locked root or service accounts that still permit password authentication in the sshd configuration.

Because the bypass requires only a single authentication attempt with a sufficiently long password, it is trivial to automate and leaves no distinctive cryptographic signature beyond the length of the password field in authentication logs.

TacticTechniqueIDRelevance
Initial AccessValid AccountsT1078Direct password-based login to accounts that should reject all passwords
Initial AccessExploit Public-Facing ApplicationT1190Remote authentication bypass against exposed sshd
PersistenceValid AccountsT1078Continued access once a session is obtained
Defense Evasion——No special evasion required; standard SSH login succeeds

Detection

Review authentication logs for successful password logins against accounts known to have * (or equivalent locked) entries in /etc/shadow. On Alpine and similar systems the relevant log lines appear in /var/log/messages, /var/log/auth.log, or the journal. A password length of 257–1024 characters in a successful Accepted password event for such an account is a high-confidence indicator.

Example pattern to search for (adjust for local logging format):

Accepted password for root from ... port ... ssh2

where the account is confirmed to have a * field and password authentication should have been impossible.

Mitigation

Immediate containment

Disable password authentication and restart sshd:

echo "PasswordAuthentication no" > /etc/ssh/sshd_config.d/00-no-passwords.conf
rc-service sshd restart

Alternatively, stop the SSH service entirely until the package is updated if the host is exposed and password authentication cannot be disabled for operational reasons.

Patch

  • Upgrade to OpenSSH 10.6p2 or later. On Alpine: apk upgrade openssh.
  • Alpine has stated it will backport the fix to 3.16 and later releases, including currently supported branches.
  • Confirm the installed version after upgrade and restart sshd.

Hardening recommendations

  • Prefer public-key authentication exclusively for all remote access.
  • Explicitly set UsePAM yes only if the distribution’s PAM configuration is known to be secure and necessary; the vulnerability exists specifically in the non-PAM path.
  • Audit /etc/shadow for accounts with * (or !) that are reachable via SSH and ensure PasswordAuthentication is disabled for them.
  • Restrict SSH exposure with network controls; many affected systems are containers or appliances that do not require inbound SSH from the internet.

Source

Detailed public analysis and interactive demonstration: sshhole.com OpenSSH 10.6p2 release announcement and notes: openssh.com release notes

Start with the intelligence you need.

Free for a limited platform. Professional for the full platform. Team for API access.

Compare plans →·More articles →