Alpine Linux OpenSSH Password Authentication Bypass: One Connection, No Password
One connection, a very long password, and a key-only account on Alpine Linux can be logged into with no valid password at all. Here is the exact condition that triggers it, who is clear, and the two commands that close the hole.
If you run sshd on Alpine Linux, the short version is: update openssh now and restart the daemon, or set PasswordAuthentication no and restart it. Either closes a hole that lets anyone who can reach your SSH port log in without knowing a password at all.
The bug is not a brute force or a timing trick. It takes one connection, works every time, and needs no retries. An attacker who knows the name of a key-only account — one whose password field is * — can authenticate as that account as long as the machine has at least one other user with a $5$ or $6$ password hash. A single real password anywhere on the box makes every passwordless account reachable.
Alpine's advisory, published on 5 November 2026, traces it to how sshd built without PAM compares passwords, and to a quirk of musl's crypt(). Details also live in the OpenSSH 10.6p2 release notes. No CVE identifier had been assigned at the time of writing.
Key takeaways
- Non-PAM
sshdon Alpine can be logged into as a passwordless account with no valid password supplied. - Two conditions are needed: a target account with
*in its password field, and at least one account with a$5$/$6$hash elsewhere on the machine. - Fixed packages ship in 3.21.10, 3.22.8, 3.23.8 and 3.24.4; upgrading does not restart the running daemon, so you must restart it yourself.
- Containers without
sshd, systems withPasswordAuthentication no, andopenssh-server-pamwithUsePAM yesare not affected. - The official tiny-cloud images are safe on first boot but become exploitable the moment any
$6$hash appears.
What actually goes wrong
When sshd is built without PAM, it checks a password by hashing the attempt with the C library's crypt() function and comparing the result to the stored password field. For an account whose stored field is too short to contain a salt — the random prefix that a hash needs — sshd borrows the salt from another account. That is where the trouble begins.
musl's crypt() returns the literal string * as an error indicator when the supplied key is longer than 256 bytes. And * is exactly what the stored password field contains for every account that has no password set. So if an attacker sends a password between 257 and 1024 bytes long, crypt() fails and hands back *, which then compares equal to the stored * — and the login is accepted.
The two ends of the comparison meet in the middle on a value that means "error", not "match". That is why the attack is deterministic: the long password is not being guessed, it is being used to force the error string.
Exactly who is affected
You are affected if all of the following hold at once. You run the Alpine openssh-server package, which is built without PAM, or you run openssh-server-pam with UsePAM no. PasswordAuthentication is yes, the OpenSSH default unless you changed it. The machine has at least one account whose password field is *, and at least one local account with a $5$ or $6$ password hash.
The accounts with * are more common than they sound. Since roughly Alpine 3.16 the base image ships root:*. Any key-only user created with adduser without a password, or set with usermod -p '*', qualifies. So do users coming from a directory service through musl-nscd — nslcd, winbind, sssd — because they have no shadow entry at all.
Root deserves a note of its own. OpenSSH's default PermitRootLogin prohibit-password protects root, so root is only directly reachable if you have set PermitRootLogin yes. That is cold comfort if another account that can log in is able to become root, for example through doas.
Who is not affected
Several common setups are clear. Docker and other container users who do not run sshd inside the container are unaffected — no daemon, no attack surface. Systems with PasswordAuthentication no are safe, and so are cloud images configured through cloud-init, because cloud-init writes PasswordAuthentication no.
On the PAM side, openssh-server-pam with UsePAM yes is not affected; it is only the UsePAM no case that is. Locked accounts are safe too: those with ! as the password field in /etc/shadow, shown as a line starting user:!:, cannot log in by password or key. And a machine where no account carries a $-style hash never meets the second condition, so there is nothing to borrow a salt from.
The fix: update and restart
The primary fix is the package update. Run apk upgrade -U -a. The fixed package lands in Alpine 3.21.10, 3.22.8, 3.23.8 and 3.24.4. Alpine's release announcement lists the exact fixed package versions per branch.
The step people miss is the restart. Upgrading the package on disk does not replace the daemon already running in memory. You have to restart it yourself with rc-service sshd restart. Until you do, the vulnerable process keeps answering connections even though the fixed binary is sitting on disk.
If you cannot update yet
Where you cannot patch immediately, disabling password authentication closes the hole on its own. Before touching anything, confirm your SSH key login works and keep your current session open until you have tested a brand-new login — a mistake here can lock you out.
Create a drop-in
mkdir -p /etc/ssh/sshd_config.dthenecho 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf. Alpine's defaultsshd_configreads that directory from 3.19 onward; older releases ignore it, which is why the next step matters.Rewrite the main config
A
sed -i.bakcommand changesyestonoon everyPasswordAuthenticationline in/etc/ssh/sshd_config, whatever the spacing and including lines inside aMatchblock. It also insertsPasswordAuthentication noat the top for the case where no such line existed, and saves the original assshd_config.bak.Validate and restart
Run
sshd -t && rc-service sshd restart. Then confirm withsshd -T | grep -i passwordauthentication, which should printpasswordauthentication no.
To undo the change later, delete /etc/ssh/sshd_config.d/00-no-passwords.conf and copy sshd_config.bak back over sshd_config.
The tiny-cloud image trap
The official tiny-cloud images — the qcow2, VHD and AMI artifacts — from 3.18.11 through 3.24.3 ship an alpine user with a * password field and passwordless doas. On first boot they are safe, because no account yet carries a $-style hash, so the second condition is absent.
They turn exploitable the moment any $6$ hash appears on the machine. That can happen quietly: an admin sets a console password, or user-data adds a user with hashed_passwd. From there an attacker gets a shell as alpine and uses the passwordless doas to become root. Images built from 3.21.10, 3.22.8, 3.23.8, 3.24.4 and later include the fixed package; images from earlier point releases do not, so on every running instance you still need to update openssh or disable password authentication.
How to tell if you were hit
Check /var/log/messages for sshd lines reading Accepted password for an account that has no password — alpine, root, or any key-only user. An accepted password for an account that was never given one is the clearest signature of this attack.
Widen the review from there. Look at recent doas use, recently created users, new files, and any additions to authorized_keys on machines that were exposed. The advisory is blunt about the judgement call: if you cannot rule out a login, treat the machine as compromised. Rebuilding from a clean image is safer than hoping a single log line tells the whole story.
Scope, gaps and what to watch
The flaw was present across a wide range of releases. Alpine says it affects every release it checked — 3.21 through 3.24 and edge — plus the older releases that no longer receive regular updates. Even those out-of-support branches got fixed packages all the way back to 3.16, and 3.21 reached its own end of support on 1 November 2026, days before the advisory.
Two things are worth tracking. First, no CVE identifier had been assigned when the advisory went out; one may land later, which matters for scanners and inventory tools that key off CVEs rather than package versions. Second, the root cause sits partly in musl's crypt() returning * for over-long keys, so watch the OpenSSH 10.6p2 release notes and musl's own channels for the authoritative description if you need to reason about other musl-based systems.
The practical lesson outlasts this particular bug: an apk upgrade that reports success is not the end of the job for a long-running service. Until sshd -T and a fresh login confirm the state you expect, assume the daemon you can reach is the one that was running before you patched.
Questions readers ask
Does upgrading the openssh package fix the running server?
No. The package on disk is replaced, but the process in memory keeps running the old binary. Run rc-service sshd restart after apk upgrade, then verify with a new login.
I use openssh-server-pam. Am I affected?
Only if you set UsePAM no. With UsePAM yes you are not affected. The plain openssh-server package is built without PAM and is affected by default.
My containers run Alpine but no sshd. Do I need to act?
No. The attack needs a reachable sshd. Containers and other systems that do not run the daemon have no exposure to this specific flaw.
Is root login a risk even with the default config?
By default PermitRootLogin prohibit-password keeps root from being reached directly. The danger is indirect: a passwordless account an attacker can log into may escalate to root through doas.
How do I confirm password authentication is really off?
Run sshd -T | grep -i passwordauthentication. It should print passwordauthentication no. If it prints yes, the config did not take effect or the daemon was not restarted.
This article draws on Transport security has blocked a cleartext HTTP and answers to it (1, 2), on the Stack Exchange network, licensed under CC BY-SA 4.0.
- #Alpine Linux security
- #PasswordAuthentication no
- #musl crypt
- #sshd vulnerability
- #tiny-cloud images



Comments