Early Light Now Detects *sshole. Sensei Fixes It.

Another day, another vulnerability.
This one is *sshole, a password bypass in OpenSSH's sshd on musl libc. Yes, that's the name. It lets a crafted password into an account whose password field is *, which on Alpine is the usual way to set up an account for key-only logins. There's no CVE yet, and the public writeup is at sshhole.com.
Early Light now detects it, and Sensei fixes it. This is No. 02 in our series: each time a new vulnerability drops, Early Light gets a detector, Sensei gets the fix, and we write it up here.
What's affected
OpenSSH's sshd from 7.3p1 through 10.6p1, built on musl libc, with password authentication on. That covers Alpine, OpenWrt, Void, and Buildroot and Yocto builds that use musl. It needs an account whose password field is exactly *.
When musl's crypt() fails, it returns *. sshd compares that result with the account's stored *, and the two match. glibc systems aren't affected, and neither are builds that check passwords through PAM (UsePAM yes).
Why it depends on another account
When sshd checks a password for a * account, it borrows the salt of the first account in /etc/passwd order that has a $-style hash. That donor decides whether crypt() fails:
| Donor hash | When crypt() fails |
|---|---|
| SHA-256 or SHA-512 | Only for passwords over 256 bytes |
bcrypt, or a bad rounds= value | For every password |
| MD5, DES or yescrypt | Never |
So two servers with the same OpenSSH package can give different answers, depending on who else has an account. A server that isn't exposed today can become exposed when someone adds a user with a SHA-512 password.
Fixed releases
OpenSSH 10.6p2 fixes it (upstream commit 4353fdc43). Alpine shipped fixed packages on November 5:
| Alpine | Fixed openssh package |
|---|---|
| 3.16 | 9.0_p1-r6 |
| 3.17 | 9.1_p1-r7 |
| 3.18 | 9.3_p2-r4 |
| 3.19 | 9.6_p1-r3 |
| 3.20 | 9.7_p1-r6 |
| 3.21 | 9.9_p2-r1 |
| 3.22 | 10.0_p1-r11 |
| 3.23 | 10.2_p1-r1 |
| 3.24 | 10.3_p1-r2 |
| edge | 10.6_p2-r0 |
Alpine 3.15 and older get no fix. OpenWrt fixed 23.05 (9.8p1-2), 24.10 (9.9_p2-2) and 25.12 (10.6_p2-1), with nothing for 22.03 and older. Void and Buildroot master are on 10.6p2. Buildroot's LTS branches and OpenEmbedded-Core were still waiting at our last check on November 5.
Alpine's backports keep the OpenSSH release number, so the version sshd reports won't tell you whether it has the fix. The package version will.
Until the package is in, two changes close the hole: set PasswordAuthentication no, and change each * password field to *NP*. *NP* still allows key logins, and no password matches it.
How Early Light knows
A package version only answers half the question. Early Light reads each sshd it finds and works through the whole condition. It identifies the C library and whether the build uses PAM. It reads the release and the apk or opkg database, where a distribution's backport shows up. It follows sshd_config through every Include and Match the way sshd does. Then it reads the accounts the way musl reads them, works out which salt sshd would pick, and names the accounts a crafted password would reach. In a container image it also reads the image's command and the startup scripts it runs, since an entrypoint that turns password logins on changes the answer. On a live server it reads the banner and the login methods on offer and never sends a password. In a source repo it reads Dockerfiles (including package lists in ARG and ENV), shell scripts, Ansible tasks, Compose and Kubernetes command overrides, Buildroot, OpenWrt and Yocto builds, and sshd_config files. When it can't settle a case, it reports unknown instead of calling you safe.
We built 10 test images with known answers (unfixed and fixed Alpine packages, password logins off, PAM on, root logins, a Match block, an entrypoint that turns password logins on at start, Debian with glibc and more). Early Light got all 10 right.
brew install defectdojo/tap/earlylight
earlylight scan image --detector sshole your-registry/your-sshd:latest
sudo earlylight scan fs --detector sshole / # this machine's sshd
earlylight scan host --detector sshole bastion.example:22 # banner and offered methods, sends no password
earlylight scan repo --detector sshole . # Dockerfiles, scripts and Ansible tasks
earlylight fix --detector sshole --dry-run . # fixed package floors, "*" to "*NP*"
Output is text, JSON or SARIF, and SARIF imports into DefectDojo.
Sensei fixes it
As of DefectDojo Pro 3.5.100, Sensei has two new checks for *sshole. The first reads your repositories: Dockerfiles, shell scripts, Ansible and cloud-init tasks, sshd_config files, and Buildroot, OpenWrt and Yocto builds. The second pulls the images your repositories build on and deploy, and judges each OpenSSH server inside them with Early Light's detector.
These fixes are deterministic. Sensei adds a floor at the fixed release to an apk install (openssh-server becomes 'openssh-server>=10.0_p1-r11' on Alpine 3.22), changes * password fields to *NP*, adds apk upgrade after a FROM line, moves an image tag to a patch release it has pulled and judged clean, re-pins digests, and adds the upstream patch to Buildroot and Yocto builds. It scans each change again before anything is written. Where a safe change isn't possible, such as turning off PasswordAuthentication, it gives you the exact manual steps.
Fight AI with AI
New vulnerabilities aren't slowing down. Our goal is the fastest detection and fix in security, every time one drops. Early Light is free and open source under the BSD 3-Clause license.
Fight AI with AI before new vulns drop tomorrow.