IT Security

SSHole: A 257-Character Password Can Log You In on Alpine Linux

How a password over 256 characters unlocks password-less accounts on Alpine and other musl Linux systems, and how to fix it.

·
3 min read
·
AI-assisted

AI tooling disclosure

Generative AI materially contributed to this article.

Human review confirmed by the author.

SSHole: A 257-Character Password Can Log You In on Alpine Linux

On November 5, 2026, OpenSSH shipped 10.6p2 to close an authentication bypass in sshd on musl-based Linux. On an affected machine, an account that should never accept a password will accept almost any password between 257 and 1,024 bytes long. It takes one connection and works every time.

The bug was reported by Özgün Kültekin of Wakefield, who wrote it up with a great timeline at sshhole.com. Here's the short version for developers.

How it works

Nothing here is a single mistake. Four old, reasonable decisions line up:

  1. * means "no password". In /etc/shadow, a field that is just * can never match any hash. This is how key-only users and many service accounts are marked.

  2. sshd borrows a salt. Without PAM, sshd checks a password by hashing it with crypt() and comparing the result to the stored field. Since the 2016 fix for a user-enumeration timing leak (CVE-2016-6210), if that field is too short to contain a salt, sshd borrows another account's salt so the check takes as long as a real one.

  3. musl's crypt() returns * on failure. Where POSIX says to return a null pointer on error, musl returns *. Its $5$ and $6$ implementations refuse keys longer than 256 bytes (a DoS limit), so an oversized password makes crypt() fail, and fail with *.

  4. Compare * to *. sshd sees that the "hash" it computed equals the stored field, and lets you in.

sequenceDiagram
    participant A as Attacker
    participant S as sshd
    participant C as musl crypt()
    A->>S: Password login as a * user, 300 characters
    S->>C: crypt(password, borrowed salt)
    C-->>S: * (error, key is over 256 bytes)
    S-->>A: Stored * equals *, login accepted

Who is affected

All of these must be true, per Alpine's advisory:

  • sshd runs on musl without PAM: Alpine's openssh-server, or openssh-server-pam with UsePAM no

  • PasswordAuthentication is yes, which is the OpenSSH default

  • An account's password field is exactly *: key-only users (created with adduser and no password, or usermod -p '*'), directory users coming through musl-nscd, root (Alpine ships root:*, but the default PermitRootLogin prohibit-password protects it), and the alpine user in tiny-cloud images

  • At least one other local account has a $5$ or $6$ hash. One is enough, and it makes every password-less account reachable

Not affected: locked accounts (!), systems with PasswordAuthentication no, openssh-server-pam with UsePAM yes, containers that don't run sshd, glibc systems, and Dropbear.

The cloud images deserve a closer look. Official tiny-cloud images from 3.18.11 through 3.24.3 ship the alpine user with passwordless doas. They are safe on first boot, but become exploitable as soon as any $6$ hash exists on the machine, for example after someone sets a console password or user-data adds a user with hashed_passwd. From there it's a password bypass, then doas to root.

What to do

Update, then restart. Upgrading the package does not restart a running sshd:

apk upgrade -U -a
rc-service sshd restart

Fixed openssh packages exist for edge and every branch back to 3.16 (for example 10.0_p1-r11 on 3.22 and 9.9_p2-r1 on 3.21). The full table is in the advisory.

If you can't update yet, turn off password logins. Keep your current session open and confirm key login works first:

mkdir -p /etc/ssh/sshd_config.d
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication   # expect: passwordauthentication no

The default config reads sshd_config.d only from 3.19 onward, and existing PasswordAuthentication lines in sshd_config, including inside Match blocks, can still win. The advisory has a sed variant that covers those cases, and the final sshd -T line tells you whether it worked.

Then check for signs of abuse. On Alpine, look for Accepted password for lines in /var/log/messages that name an account with no password:

grep "Accepted password for" /var/log/messages

If you find one you can't explain, treat the host as compromised: review doas use, new users, changed files, and authorized_keys.

The takeaway

OpenSSH's release notes call 10.6p2 a workaround in sshd and say the root cause sits outside it. The advisory said no CVE had been assigned yet; CVE-2026-123158 has since been widely reported, so check NVD for the current record.

The lesson goes beyond SSH: an error return should never be able to look like valid data.

Sources

Comments(0)

Join the discussion by logging into your account.

No comments yet. Be the first to comment!

Anshu Pathak

Passionate developer sharing knowledge about modern web technologies and best practices.

Subscribe to Anshu Pathak's Newsletter

Direct email dispatches when new stories are published. Zero algorithms.