Security advisory · OpenSSH 10.6p2 · Disclosed 2026-11-05
*sshole
Published
On OpenSSH built against musl libc and checking passwords without PAM, any account whose /etc/shadow field is exactly * accepts any password of 257 to 1024 characters. That covers key-only users, directory users, a locked root and the alpine user in Alpine's cloud images. It takes one connection and no retries.
Disclosed and fixed on 2026-11-05 in OpenSSH 10.6p2, with backported Alpine packages for every branch from 3.16 to edge. No CVE was assigned at disclosure. glibc hosts, and hosts that authenticate through PAM, are not affected.
- Impact
- Password login as any account whose shadow field is *
- Affected
- OpenSSH on musl (Alpine, OpenWrt, buildroot, yocto), password auth without PAM
- Fixed in
- OpenSSH
10.6p2, or your distro's package release - Needs
- A reachable * account and one $5$ or $6$ password hash
- Reported by
- Özgün Kültekin of Wakefield
[01]
One error string, every * account
How it works
* equals *
Without PAM, sshd checks a password by hashing the attempt with crypt() and comparing the result to the stored field. A * field holds no salt, so sshd borrows one from an account that has a $5$ or $6$ hash. musl's crypt() returns * as an error when the key runs past 256 bytes, and that matches the stored *.
musl crypt("A"×256, "$6$salt$") → $6$salt$<88-char hash> (rejected)
musl crypt("A"×257, "$6$salt$") → * (== stored "*")OpenSSH 10.6p2 rejects any stored hash shorter than four characters. The root cause is in musl, but sshd is where it is exploitable, so that is where it is fixed.
Fixed Alpine releases
The fixed packages per branch, from Alpine's advisory as of 2026-11-05:
| Alpine branch | Fixed openssh release |
|---|---|
| edge | 10.6_p2-r0 |
| 3.24 | 10.3_p1-r2 |
| 3.23 | 10.2_p1-r1 |
| 3.22 | 10.0_p1-r11 |
| 3.21 | 9.9_p2-r1 |
| 3.20 | 9.7_p1-r6 |
| 3.19 | 9.6_p1-r3 |
| 3.18 | 9.3_p2-r4 |
| 3.17 | 9.1_p1-r7 |
| 3.16 | 9.0_p1-r6 |
Alpine 3.21.10, 3.22.8, 3.23.8 and 3.24.4 ship the fixed package. 3.16 to 3.21 are past regular support, but each got a fixed package.
[A]Mitigations
- Upgrade openssh and restart sshd: upgrading the package does not replace the running daemon.
- Stopgap:
PasswordAuthentication noin ansshd_config.ddrop-in. - Stopgap on Alpine: the
openssh-server-pambuild withUsePAM yes. - Containers: rebuild the image on a fixed openssh rather than patching the running container.
[B]Signs of a login
Look in /var/log/messages for sshd lines reading Accepted password for an account that has no password: alpine, root or any key-only user. If you cannot rule a login out, treat the machine as compromised.
[C]Known limits
- An Alpine branch outside the table cannot be proven patched from its version.
- A non-Alpine musl build (OpenWrt, buildroot) whose vendor backported the fix keeps the upstream version, so it reads as vulnerable below 10.6p2.
[02]
Check and fix with Swamp
Step 1:Am I affected?
A machine is exposed only when all of these hold at once.
- musl libc: Alpine, OpenWrt, buildroot, yocto.
- An unfixed OpenSSH: below 10.6p2 upstream, or below your distro's fixed package release.
- No PAM on the password path: Alpine's
openssh-serverhas none;openssh-server-pamwithUsePAM yesis safe. PasswordAuthentication yes, the OpenSSH default.- A reachable * account. A
*root counts only underPermitRootLogin yes, but any other*account that can become root, for example throughdoas, is as good as root. - A salt seed: at least one account with a
$5$or$6$hash. A fresh box with every account locked is safe until the first real password is set.
Distributions backport the fix without changing the OpenSSH version, so
ssh -Vcannot tell patched from vulnerable: the package release decides. Alpine's tiny-cloud images from 3.18.11 through 3.24.3 ship analpineuser with a*field and passwordlessdoas; they become exploitable as soon as any$6$hash exists.Step 2:Install Swamp and the scanner
The @swamp/cve/sshole extension has one method,
scan. It reads the target and reports a verdict. It never logs in over SSH, never tries a password and never changes the target.Install Swamp:
curl -fsSL https://swamp-club.com/install.sh | shInitialize a new repo (run this in a new empty directory):
swamp repo initPull the scanner:
swamp extension pull @swamp/cve/ssholeCreate a scanner for this machine:
swamp behavior create @swamp/cve/sshole sshole-scannerAm I vulnerable (run as root so it can read /etc/shadow):
swamp behavior run sshole-scanner scanStep 3:Scan a container or an image
Set
dockerContainerto scan a running container throughdocker exec, ordockerImageto start a container from an image, scan it and remove it. Set one or the other, not both; with neither,scanreads the local machine.swamp behavior create @swamp/cve/sshole sshole-web \ --global-arg dockerContainer=web swamp behavior run sshole-web scanswamp behavior create @swamp/cve/sshole sshole-app-image \ --global-arg dockerImage=registry.example.com/app:1.4 swamp behavior run sshole-app-image scan›Scan results
Three images built for this page: Alpine 3.15 on openssh 8.8 with a key-only
deployaccount, Alpine 3.20 on the fixed9.7_p1-r6, and Debian bookworm.# *sshole (OpenSSH musl password bypass) 1 target(s) scanned — 1 vulnerable, 0 not vulnerable, 0 unknown. ┌─────────────────────────┬────────────┬──────────┬──────┬───────────────┬─────────┬────────┬───────────┐ │ Target │ Verdict │ Risk │ libc │ OpenSSH │ PAM │ PwAuth │ '*' accts │ ├─────────────────────────┼────────────┼──────────┼──────┼───────────────┼─────────┼────────┼───────────┤ │ sshole-demo:alpine-3.15 │ VULNERABLE │ CRITICAL │ musl │ OpenSSH_8.8p1 │ unknown │ yes │ 1 │ └─────────────────────────┴────────────┴──────────┴──────┴───────────────┴─────────┴────────┴───────────┘ ## sshole-demo:alpine-3.15 — VULNERABLE Exposed: 1 reachable '*' account(s) (deploy) accept any 257–1024 character password. '*' accounts: * `deploy` * sshd is not linked against / does not have PAM for password auth. * 1 reachable '*' account(s); on musl a password over 256 bytes hashes to '*' and matches. * 1 account(s) carry a $5$/$6$ hash to seed the borrowed salt. ## Recommendations * Upgrade openssh to 10.6p2 or newer (apk upgrade -U -a) and restart sshd. * This looks like a container: rebuild the image on a fixed OpenSSH rather than patching the running container. ## Stopgaps until patched * Set 'PasswordAuthentication no' in /etc/ssh/sshd_config.d/00-sshole.conf and restart sshd. * On Alpine, the openssh-server-pam build with 'UsePAM yes' is not affected. Fixed in OpenSSH 10.6p2 (2026-11-05). No CVE was assigned at disclosure. glibc hosts and hosts that authenticate through PAM are not affected.# *sshole (OpenSSH musl password bypass) 1 target(s) scanned — 0 vulnerable, 1 not vulnerable, 0 unknown. ┌─────────────────────────┬────────────────┬──────┬──────┬───────────────┬─────────┬────────┬───────────┐ │ Target │ Verdict │ Risk │ libc │ OpenSSH │ PAM │ PwAuth │ '*' accts │ ├─────────────────────────┼────────────────┼──────┼──────┼───────────────┼─────────┼────────┼───────────┤ │ sshole-demo:alpine-3.20 │ NOT VULNERABLE │ NONE │ musl │ OpenSSH_9.7p1 │ unknown │ yes │ 2 │ └─────────────────────────┴────────────────┴──────┴──────┴───────────────┴─────────┴────────┴───────────┘ ## sshole-demo:alpine-3.20 — NOT VULNERABLE Patched: 9.7_p1-r6 carries the fix. * patched: Alpine 3.20 openssh 9.7_p1-r6 includes the fix (≥ 9.7_p1-r6, Alpine 3.20). Fixed in OpenSSH 10.6p2 (2026-11-05). No CVE was assigned at disclosure. glibc hosts and hosts that authenticate through PAM are not affected.# *sshole (OpenSSH musl password bypass) 1 target(s) scanned — 0 vulnerable, 1 not vulnerable, 0 unknown. ┌─────────────────────────────┬────────────────┬──────┬───────┬─────────────┬─────┬────────┬───────────┐ │ Target │ Verdict │ Risk │ libc │ OpenSSH │ PAM │ PwAuth │ '*' accts │ ├─────────────────────────────┼────────────────┼──────┼───────┼─────────────┼─────┼────────┼───────────┤ │ sshole-demo:debian-bookworm │ NOT VULNERABLE │ NONE │ glibc │ OpenSSH_9.2 │ yes │ yes │ 19 │ └─────────────────────────────┴────────────────┴──────┴───────┴─────────────┴─────┴────────┴───────────┘ ## sshole-demo:debian-bookworm — NOT VULNERABLE Not affected: glibc libc. * libc is glibc; the bypass only affects OpenSSH built against musl. Fixed in OpenSSH 10.6p2 (2026-11-05). No CVE was assigned at disclosure. glibc hosts and hosts that authenticate through PAM are not affected.Step 4:Read the verdict
Every scan leads with one of three verdicts, and a risk level from
criticaltonone.vulnerable: every precondition holds, and the report names the*accounts that accept a long password.not-vulnerable: a precondition is missing, such as glibc, a fixed release, PAM or password auth turned off.unknown: the scanner could not decide. Most often it ran without root and could not read/etc/shadow; rerun as root. No sshd at all, or a setting that could only be read from the config files becausesshd -Tfailed, is also unknown. The report says which input was missing.
To upgrade and restart sshd on Alpine:
apk upgrade -U -a rc-service sshd restartIf you cannot upgrade yet, turn password logins off. Keep a working key login and your current session open until a new login succeeds. Alpine reads the drop-in directory from 3.19 on; on older releases set it in
/etc/ssh/sshd_configinstead.mkdir -p /etc/ssh/sshd_config.d echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-sshole.conf sshd -t && rc-service sshd restart sshd -T | grep -i passwordauthentication›An unknown result
# *sshole (OpenSSH musl password bypass) 1 target(s) scanned — 0 vulnerable, 0 not vulnerable, 1 unknown. ┌─────────────────────────────────┬─────────┬──────┬──────┬───────────────┬─────────┬─────────┬───────────┐ │ Target │ Verdict │ Risk │ libc │ OpenSSH │ PAM │ PwAuth │ '*' accts │ ├─────────────────────────────────┼─────────┼──────┼──────┼───────────────┼─────────┼─────────┼───────────┤ │ sshole-demo:alpine-3.15-nonroot │ UNKNOWN │ HIGH │ musl │ OpenSSH_8.8p1 │ unknown │ unknown │ ? │ └─────────────────────────────────┴─────────┴──────┴──────┴───────────────┴─────────┴─────────┴───────────┘ ## sshole-demo:alpine-3.15-nonroot — UNKNOWN Likely exposed: musl, non-PAM, password auth on — rerun as root to list '*' accounts and the salt seed. * sshd is not linked against / does not have PAM for password auth. * /etc/shadow is not readable, so '*' accounts were not listed. Not checked: PasswordAuthentication (defaults to on); salt-seeding $5$/$6$ account (need root to read /etc/shadow). ## Recommendations * Rerun as root to confirm the exposed accounts. * Upgrade openssh to 10.6p2 or newer (apk upgrade -U -a) and restart sshd. ## Stopgaps until patched * Set 'PasswordAuthentication no' in /etc/ssh/sshd_config.d/00-sshole.conf and restart sshd. * On Alpine, the openssh-server-pam build with 'UsePAM yes' is not affected. Fixed in OpenSSH 10.6p2 (2026-11-05). No CVE was assigned at disclosure. glibc hosts and hosts that authenticate through PAM are not affected.
[03]
References
Find every exposed sshd
Pull the scanner and run it on every Alpine host, container and image you ship.
swamp extension pull @swamp/cve/sshole