Jorge Turbica / blog · Blog ← All articles ES · Leer en español
Technologies

A 257-byte password opens sshd on Alpine without PAM: patch OpenSSH now

A musl and sshd interaction lets attackers log in over SSH with no password on Alpine 3.16 to 3.24. Which hosts are exposed and how to fix it.

One connection, no retries and a password between 257 and 1024 bytes long: that is all it takes to log in over SSH to an Alpine Linux box running sshd without PAM, without knowing a single password. Alpine published the advisory on 5 November 2026, the same day OpenSSH shipped 10.6p2 with the fix, and every branch the Alpine team checked is affected, from 3.16 to 3.24 and edge. No CVE had been assigned when the advisory went out, so don't wait for your vulnerability scanner to flag it.

Why the attack works

Without PAM, sshd checks passwords itself: it runs crypt() on the attempt and compares the result with the field in /etc/shadow. When that field is too short to hold a salt, like the * on accounts with no password, sshd borrows the salt from another account that does have a hash.

The catch is how musl's crypt() handles a key longer than 256 bytes: it returns the string * as an error marker. And * is exactly what the password field holds on every account without a password. The "hash" matches and the login goes through. OpenSSH considers the root cause to live outside sshd, but since it is exploitable through it, 10.6p2 blocks it in its own code.

Are you affected?

All of these have to be true:

  • You run Alpine's openssh-server package, which is built without PAM, or openssh-server-pam with UsePAM no.
  • PasswordAuthentication is yes, which is the OpenSSH default.
  • Some account has * as its password field: root in the base image since 3.16, key-only users created with adduser and no password, directory users through musl-nscd, or the alpine user in tiny-cloud images.
  • At least one local account has a $5$ or $6$ hash. One is enough to expose every passwordless account.

root itself is covered by the default PermitRootLogin prohibit-password, but that buys you little if another reachable account can escalate through doas.

The nastiest case is the official tiny-cloud images (qcow2, VHD and AMI) from 3.18.11 through 3.24.3. They ship an alpine user with * and passwordless doas. They are safe on first boot, but the moment a $6$ hash lands on the machine, say because someone sets a console password or user-data adds a user with hashed_passwd, an attacker gets a shell as alpine and root via doas.

You are not affected if your containers don't run sshd, if you have PasswordAuthentication no, if you use openssh-server-pam with UsePAM yes, for accounts locked with !, or on images configured by cloud-init, which already writes PasswordAuthentication no. According to OpenSSH, the bug is limited to Linux systems with musl and PAM disabled: Debian, Ubuntu and RHEL use glibc and usually build sshd with PAM.

How to update

The short path is to upgrade and, crucially, restart the daemon: the new package does not replace the sshd that is already running.

bash
apk upgrade -U -a
rc-service sshd restart

Fixed versions per branch, including branches that no longer get regular updates:

BranchFixed openssh version
edge10.6_p2-r0
3.2410.3_p1-r2
3.2310.2_p1-r1
3.2210.0_p1-r11
3.219.9_p2-r1
3.209.7_p1-r6
3.199.6_p1-r3
3.189.3_p2-r4
3.179.1_p1-r7
3.169.0_p1-r6

Point releases 3.21.10, 3.22.8, 3.23.8 and 3.24.4 already include the fixed package, and so do images built from them. An instance booted from an older image stays vulnerable until you upgrade the package on it: rebuilding the image does nothing for machines already running.

If you can't upgrade right now, turning off password logins closes the hole just as well. First make sure key login works and keep your current session open until you've tested a fresh login. These are the commands from Alpine's advisory (the default config reads sshd_config.d from 3.19 onward; the sed covers older releases and Match blocks):

bash
mkdir -p /etc/ssh/sshd_config.d
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
sed -i.bak -e '1i PasswordAuthentication no' \
  -e 's/^\(\s*PasswordAuthentication[^y#]*\)yes/\1no/i' \
  /etc/ssh/sshd_config
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication

The last line should print passwordauthentication no.

Post-patch checklist

  • apk info -v openssh-server (or openssh-server-pam) shows the fixed version for your branch.
  • The sshd process was restarted after the upgrade, not just the package.
  • sshd -T | grep -i passwordauthentication returns what you expect on every host, including those built from tiny-cloud images older than 3.24.4.
  • Search /var/log/messages for Accepted password for lines on accounts that have no password (alpine, root or key-only users). Also review doas usage, recently created users and authorized_keys on exposed machines. If you can't rule out a login, Alpine says to treat the machine as compromised.

What strikes me most is the chain: neither musl nor sshd does anything absurd on its own, but an error value that happens to equal a legitimate value turns an implementation detail into a full bypass. It also fits the note at the top of the 10.6p2 release notes: the OpenSSH team is getting a flood of AI-assisted reports, has seen bugs found that way later rediscovered independently by someone else, and will ship releases more often instead of batching fixes. If you run internet-facing Alpine hosts, PasswordAuthentication no should be your baseline, patch or no patch.

Sources

Jorge Turbica

Software Engineer and SRE. I write about the real challenges I run into in production.

See portfolio ↗