*sshole: Auth bypass on blocked accounts on Linux
8.10
CVE-2026-123158
Description
From 2016 to 2026, MUSL-based Linux distributions like Alpine and OpenWRT, including Alpine-based Docker images, had a flaw. Accounts which are locked to prevent password login had their entry in `/etc/shadow` contain an asterix (\*). The logic was clear - there is no password of which the hash would be a '\*', effectively disabling password login.
`f(x) != *` for any value of x.
On the other side, musl makes a change to their `crypt()` function. Since handling NULL values was not exactly in fashion, they decided to return a single character, which cannot ever match the actual password. Tragically, they also settled on the '\*' character rather than returning NULL in the case of an error.
These two changes, while decades apart, suddenly made the impossible happen. At the same time, the stored password hash of an account for which password login was disabled was a '\*', and the error value returned from `crypt()` was also a '\*', allowing login to such blocked accounts.
But what can cause `crypt()` to return an error? Maybe if an algorithm is required but isn't installed. Well, actually, musl went on to cause passwords of length greater than 256 to error out to prevent excessive compute load with sha512.
All these coincidences put together mean that typing in a password longer than 256 bytes when ssh'ing into an account which blocks password login, causes the return value from `crypt()` to match the stored hash.
Reproduction
I will keep this part short because I have to go make Divali cakes, and I just wanted to push this post out so I have something to show on the page. The following is from a post on Mastodon I lost the link to.
1. To log onto `root` as demonstrated in the POC, you need PermitRootLogin, which is almost never set to "yes". If you have it set to "yes", you are living dangerously.
2. Only root shipped with '\*' in the hash field. Every other account ships with an '!' instead, which will not match crypt's error value of '\*'.
Details