← All writing

SSHole: How a 257-Byte Password Broke SSH on Alpine Linux

CVE-2026-123158 is a high-severity OpenSSH authentication bypass on musl-based Linux without PAM. A collision between two reasonable decisions made years apart lets any long password log in to accounts that have no password. Here is what happened, who is affected, and what to patch today.

· Updated 2026-11-07

  • Security
  • OpenSSH
  • CVE-2026-123158
  • Alpine Linux
  • DevOps

SSHole: How a 257-Byte Password Broke SSH on Alpine Linux

On November 5, 2026, OpenSSH shipped an emergency release - 10.6p2 - fixing a password authentication bypass in sshd that its own team described as critical. The flaw, tracked as CVE-2026-123158 and nicknamed *sshole by its finder, lets anyone who can reach port 22 log in to accounts that have no password at all, using any password between 257 and 1,024 bytes. One connection, every time.

This is not a broken cipher or a memory-corruption exploit. It is a collision between two sensible engineering decisions, made in different projects four years apart, that only became dangerous when combined with a third.

Who is actually affected

The bug requires all four of these conditions (Alpine's advisory):

  • sshd runs on musl libc and checks passwords without PAM - exactly how Alpine's default openssh-server package is built
  • PasswordAuthentication yes - the OpenSSH default
  • An account that can log in has * in its shadow password field (a key-only user, or the alpine user on tiny-cloud images)
  • At least one other local account has a $5$/$6$ hash

That covers most Alpine servers and VMs by default, plus embedded devices built with Buildroot or Yocto that installed OpenSSH. It does not affect glibc distributions (Debian, Ubuntu, RHEL, Fedora), macOS, OpenBSD, or any sshd authenticating through PAM. Dropbear - OpenWrt's default SSH server - is also unaffected.

The uncomfortable part: on Alpine's official tiny-cloud images (3.18.11–3.24.3), the alpine user ships with no password and passwordless doas. The moment any admin sets a password somewhere on the box, the host silently becomes exploitable - and a successful login as alpine is one doas away from root.

How the flaw works

Without PAM, sshd verifies passwords itself: it runs the attempt through crypt() and compares the result with the field in /etc/shadow. A real hash looks like $6$salt$…; an account with no password is marked with a bare *, which nothing should ever match.

Three ingredients turned that into a bypass:

  1. musl's crypt() returns the string "*" on failure - a deliberate choice so callers that ignore errors get "wrong password" instead of a crash.
  2. musl caps SHA-crypt inputs at 256 bytes (a CPU-exhaustion defense). A longer password fails - and failure returns "*".
  3. A 2016 OpenSSH fix for a username-enumeration timing flaw (CVE-2016-6210) made sshd hash attempts even for passwordless accounts, borrowing another account's salt - which is why one real $5$/$6$ hash on the host is enough to arm the attack.

So: send a 257-byte password to a * account → musl refuses it, returns "*" → sshd compares "*" with the stored "*" → match → welcome aboard. glibc returns a different failure value, and PAM never calls crypt() for a * account - which is why everyone else was safe.

OpenSSH 10.6p2 closes it by rejecting any match where the stored hash is shorter than 4 characters. The release notes are explicit that the root cause lives outside sshd; musl's maintainer counters that this is erroneous use of the API, not a musl bug, and expects a behavior change in the next release cycle. For operators, none of that changes the to-do list.

What to do today

  1. Identify exposed hosts. Run on each candidate: sshd -T | grep -Ei '^(usepam|passwordauthentication) ' - no usepam line at all means no PAM. Then awk -F: '$2=="*" {print $1}' /etc/shadow to list passwordless accounts.
  2. Update and restart sshd. apk upgrade does not replace the running daemon - the host stays exposed until rc-service sshd restart. Alpine backported fixes to every branch back to 3.16, including out-of-support releases.
  3. Can't patch yet? Set PasswordAuthentication no. This closes the hole completely (Alpine's, OpenSSH's, and musl's shared recommendation). Verify key login works before restarting, and check Match blocks that may re-enable it.
  4. Hunt for compromise. An Accepted password for log line naming a passwordless account cannot happen legitimately. If you find one you cannot explain, treat the machine as compromised: rebuild, rotate secrets.

As of publication there is no CISA KEV entry and no reported in-the-wild exploitation - but the bug has been reachable since 2016, public repro labs are public, and the attack is just a long password over a normal SSH connection. Absence of reports is not evidence of absence.

The two lessons

Defense-in-depth had a seam. PAM existed, and using it would have made this bug irrelevant. The default package chose the leaner path, and a decade of reasonable decisions compounded into an auth bypass. Worth auditing where your own stack defaults to "lean" over "layered".

AI-assisted discovery is here. The finder reports finding *sshole by running ~17,600 unusual logins across sshd builds with AI agents, and the OpenSSH team's release notes say it has seen "a large number" of AI-reported security bugs - including cases where the same bug was independently found by a second researcher. Their conclusion is blunt: if AI tools can find these, so can adversaries. OpenSSH is moving to more frequent releases rather than batching fixes. Expect the vulnerability tempo to keep accelerating - patch cadence, not cleverness, is the defense.


Sources: OpenSSH 10.6p2 release notes · Alpine advisory · CVE-2026-123158 · *sshole write-up · musl-list advisory

Sources

Command palette

↑↓ navigate · Enter select · Esc close