Any password between 257 and 1,024 bytes logs you into a passwordless account on a stock Alpine Linux box running sshd. One connection, one attempt, works every time. OpenSSH shipped 10.6p2 on November 5 as a workaround, Alpine pushed fixed packages for every release back to 3.16 the same day, and the two pieces of code that combine to cause it were both written in 2012.
The bug is now CVE-2026-123158. The researcher who found it, Özgün Kültekin of Wakefield, named it sshole. The name is accurate.
Three old decisions and one borrowed salt
When sshd is built without PAM, it checks passwords itself. It calls crypt() on what the client sent and compares the result to the field stored in /etc/shadow. On glibc systems that's fine. On musl, two things happen that nobody connected for fourteen years.
In August 2012, musl changed crypt() to return the string * on failure instead of NULL. The commit message said it was meant to return "an unmatchable hash." Twenty days later, musl added SHA-256 and SHA-512 crypt with a 256 byte cap on the password, as denial of service protection. Anything longer fails, and failure returns *.
Now look at what Alpine stores for an account with no password. It stores *. Root has shipped as root:* since Alpine 3.16 in 2022. A user you create with adduser and no password gets *. Users pulled from LDAP through musl-nscd have no shadow entry at all, which sshd treats the same way. The whole point of * is that no hash can ever equal it. Except on musl, one can, and the attacker picks it by sending a long password.
There's one more piece. A bare * is too short to hold a salt, so sshd can't hash against it. Since the 2016 fix for CVE-2016-6210 (a timing side channel for username enumeration), sshd borrows the salt from another account's real hash when the target account's field is unusable. That path exists to make invalid users look like valid ones. It also fires for valid users whose field is *. So the attack needs one other local account with a $5$ or $6$ hash, which on any machine with a single human user is a given.
Put it together. Attacker sends 300 bytes of garbage as the password for root or any key only user. sshd borrows a salt, hands the password to musl's crypt(), musl rejects the length and returns *. sshd compares * to *. Match. Shell.
Kültekin found it by building sshd in every combination of glibc, musl, PAM, no PAM, shadow and no shadow, then running about 17,600 login attempts with broken hashes and long passwords against each build. Every build agreed except musl without PAM. The writeup also notes that an unrelated OpenSSH commit touching the fake salt code for bcrypt landed on October 30, four lines above the bug, and nobody saw it then either.
Who is exposed, and who is not
The Alpine advisory lists four conditions, and all four must hold:
- sshd is the openssh-server package (built without PAM), or openssh-server-pam with UsePAM no.
- PasswordAuthentication is yes. That is the OpenSSH default.
- At least one account has * as its password field.
- At least one other local account has a SHA-256 or SHA-512 hash.
Root is partly covered by PermitRootLogin prohibit-password, which is also the default. But any key only user who can run doas is a root shell with one extra step. Alpine's official cloud images, the qcow2, VHD and AMI builds from 3.18.11 through 3.24.3, ship an alpine user with a * field and passwordless doas. They're safe on first boot and exploitable the moment any $6$ hash lands on the machine, for example from a console password set in user data. Images built from cloud-init are not exposed because cloud-init writes PasswordAuthentication no.
Containers that don't run sshd are fine, which is most of them. Containers that do run sshd, and there are more of those than people admit, are not. OpenWrt uses Dropbear by default, which isn't affected, but any OpenWrt, Buildroot or Yocto build that swapped in OpenSSH on musl needs checking. Debian, Ubuntu, Fedora and RHEL are glibc and PAM and are not affected. OpenBSD is not affected.
The CVSS score is 8.1. Treat that number as a formality. On a machine that meets the four conditions, this is remote root with no credentials and no exploit development, and the proof of concept is a long string.
The fix, and the version number trap
Upstream 10.6p2 refuses to match any stored field shorter than four characters. OpenSSH calls this a workaround and says the root cause lies outside sshd. Damien Miller's list announcement says the team learned of the bug on November 4 and released on November 5, and gives the reason: the project has watched AI agents rediscover reported bugs within hours, and Miller now considers long embargo periods to mostly benefit attackers. The release notes add that OpenSSH is getting many AI assisted reports and will cut releases more often for now.
Alpine's stable packages carry their own backport, so a patched Alpine box will not say 10.6p2. On 3.24 the fixed package is 10.3_p1-r2. On 3.22 it's 10.0_p1-r11. On 3.16, which went out of support years ago, it's 9.0_p1-r6. Any scanner that keys on the version banner will flag patched hosts and may pass unpatched ones. Check the apk version or test the behavior.
The other trap is the restart. apk upgrade does not restart a running sshd. The advisory spells out both steps, and I'd put them in that order in every runbook:
apk upgrade -U -a
rc-service sshd restart
If you can't patch yet, turn off password authentication. Confirm key login works first and keep your current session open. Drop a file in /etc/ssh/sshd_config.d/ containing PasswordAuthentication no, fix every PasswordAuthentication yes line in the main config including inside Match blocks, run sshd -t, restart, then confirm with sshd -T | grep -i passwordauthentication. The drop-in directory is only read by default from 3.19 onward.
Then go look at your logs. Grep /var/log/messages for "Accepted password for" against any account that has no password. Alpine's own wording is that if you cannot rule out a login, treat the machine as compromised. No exploitation in the wild had been reported as of November 5, and the CVE is not in CISA's catalog of known exploited vulnerabilities. That covers yesterday. The week after a 2,600 point Hacker News thread with the payload in it is a different question.
Password auth was the bug all along
Every condition in that list is a default. Alpine's sshd is built without PAM by default. Password authentication is on by default. Root is * by default. The only reason most Alpine hosts are not exposed is that most of them have no sshd at all. The ones that do, the small VPS, the jump host, the build runner, the appliance someone built on Alpine because it was 5 MB, those are the ones that have been reachable with a long string since 2022.
I've run SSH on the public internet for a long time, and the one rule that has held through every OpenSSH advisory is that password authentication should be off everywhere. Password strength has nothing to do with it. The password path has more code in it than the key path, that code touches libc and PAM and shadow in ways that differ per distribution, and this is the second time in a decade a bug in that path (the 2016 enumeration fix was the first) has turned into a story. With PasswordAuthentication no and keys, none of this touches you, patched or not.
Alpine will get the blame this week, and the advisory is good work: fixed packages back to 3.16 in a day, with 3.21 having left support on November 1. But the bug sits between three projects. musl chose a return value in 2012 that the Single UNIX Specification doesn't allow. OpenSSH built a salt borrowing path in 2016 that never expected crypt() to return a valid looking string on failure. Alpine chose * for root in 2022 to fix an earlier CVE. Each decision was reasonable on its own. Nobody owned the join. Debian asked glibc to copy musl's * behavior in 2013, and the only reason glibc systems aren't on this list is that Debian later moved to libxcrypt, which returns *0, which is two characters and doesn't match.
My prediction: within a month someone will find a second musl without PAM edge case in the same function, because 17,600 logins is a small test matrix and Miller just told every agent operator where to point. Patch now, and turn off passwords while you're in there.