← Back to Feed CACHED · 2026-11-05 21:24:03 · CACHE_KEY CVE-2026-123158
CVE-2026-123158 · CWE-394 · Disclosed 2026-11-05

OpenBSD OpenSSH sshd password authentication bypass on musl libc without PAM

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A keyless lock that opens when you jiggle the handle with a very long password

OpenSSH before 10.6p2 has an authentication bypass when built against musl libc with UsePAM no — the exact configuration used by Alpine Linux's default openssh-server package. When sshd verifies a password, it calls musl's crypt(). If the supplied password is 256–1024 characters, musl returns * as an error sentinel, and sshd then compares that * against the stored password hash for accounts that have no password set (*). The strings match, and the login succeeds. Affected versions: OpenSSH 0 through <10.6p2 on musl/no-PAM Linux, fixed in 10.6p2.

Vendor severity HIGH (8.1) overstates the real exposure because the vulnerable population is narrow: only musl/no-PAM systems, and only accounts whose password field is * and whose shell allows SSH login. glibc distros (Debian, Ubuntu, RHEL) and sshd with PAM enabled are not affected. On most production systems, root is blocked by PermitRootLogin prohibit-password and service accounts have /sbin/nologin, so the practical default exploitability is lower than 'remote unauth root'.

"Locked accounts on Alpine sshd can be opened with a 256+ char password — patch OpenSSH, but don't panic for glibc fleets."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find exposed sshd on a musl Linux host

Attacker uses Shodan/Censys or direct port scans to locate TCP/22 running OpenSSH on musl-based distributions, most commonly Alpine Linux. The OpenSSH banner reveals the version but not the libc; OS fingerprinting or follow-up probes identify Alpine. Affected builds are OpenSSH <10.6p2 linked to musl and compiled without PAM.
Conditions required:
  • Network access to the SSH port
  • OpenSSH <10.6p2 on musl/no-PAM
Where this breaks in practice:
  • Most enterprise Linux is glibc and unaffected
  • SSH is often restricted to VPN/jump-host segments
Detection/coverage: Shodan/Censys can enumerate exposed SSH; IONIX flags SSH services accepting password login as SSH weak auth.
STEP 02

Confirm vulnerable sshd configuration

Attacker verifies UsePAM no and PasswordAuthentication yes by attempting a long-password login or by using research tools; a valid account with a real password will reject the long password, but a * account will accept it. No scanner method reliably reports config without shell access, so the attacker may simply try candidate accounts.
Conditions required:
  • UsePAM no and PasswordAuthentication yes
  • Account with stored password hash * and valid shell
Where this breaks in practice:
  • Hardened baselines disable password auth
  • Root is usually blocked by PermitRootLogin prohibit-password
Detection/coverage: Local audit command awk -F: '$2=="*" && $7 !~ /(nologin|false)/{print $1}' /etc/shadow identifies candidates.
STEP 03

Send a 256–1024 character password

Any SSH client (OpenSSH ssh, Paramiko, sshpass) is given a long password. musl's crypt() returns * for passwords longer than 256 bytes, matching the * hash for a no-password account. The login succeeds without knowing any actual credential.
Conditions required:
  • Password length 256–1024 bytes
  • No account lockout or MaxAuthTries limit reached
Where this breaks in practice:
  • This step is trivial; the difficulty is entirely in the preceding preconditions
Detection/coverage: SIEM can alert on successful SSH login for a locked/no-password account with a long password if authentication logging is centralised.
STEP 04

Obtain shell access as the bypassed account

The attacker drops into the shell of the no-password account. Because the account is likely unprivileged and root is normally excluded by sshd policy, the immediate impact is usually a low-privilege local shell, with lateral movement depending on the host and environment.
Conditions required:
  • Valid login shell on the account
  • Account permitted by AllowUsers/DenyUsers/DenyGroups
Where this breaks in practice:
  • Service accounts often have /sbin/nologin or /bin/false
  • Non-root account may have limited privileges
Detection/coverage: EDR/host agent can flag unusual process ancestry for an SSH session.
03 · Compensating Control

1
MEDIUM 5.5→IGNORE 0.0
SEVERITY REDUCED
Patch OpenSSH to 10.6p2 or upgrade Alpine (apk upgrade -U -a) and restart sshd — This removes the crypt() comparison flaw. Remediate within 365 days under the noisgate remediation SLA for MEDIUM; no mitigation SLA applies, but affected Alpine hosts with no-password accounts should be prioritized in the patch cycle.
2
MEDIUM 5.5→IGNORE 0.0
SEVERITY REDUCED
Disable PasswordAuthentication in /etc/ssh/sshd_config and restart sshd — Immediately blocks the attack path if you cannot patch yet. Ensure working pubkey access first. Under MEDIUM there is no mitigation SLA, but this can be done at the next change window or immediately on high-risk hosts.
3
MEDIUM 5.5→IGNORE 0.0
SEVERITY REDUCED
Audit /etc/shadow for accounts with * password field and valid shells; lock or assign passwords — Removes the account precondition. Use awk -F: '$2=="*" && $7 !~ /(nologin|false)/{print $1}' /etc/shadow. For service accounts run passwd -l <user> or usermod -s /sbin/nologin <user>.
4
MEDIUM 5.5→LOW 2.0
SEVERITY REDUCED
Restrict SSH exposure at network perimeter / host firewall — Limit TCP/22 to jump hosts/VPN segments. This reduces remote reachability; perform during the same remediation window if external exposure is confirmed.
What doesn't work
  • Enabling UsePAM yes on Alpine without testing often breaks sshd authentication or is unavailable in minimal musl builds; it is not a drop-in mitigation.
  • Fail2ban/account lockout won't help because the attacker succeeds on the first attempt with any long password, and the account may not have failed logins.
  • Replacing musl crypt() behavior locally is not a user-level mitigation; source patch or vendor package is required.
04 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo known exploitation in the wild; CISA KEV not listed as of 2026-11-05.
PoC availabilityTrivially reproducible; IONIX reports public reproduction labs. No weaponized PoC, Nuclei template, or OpenVAS check yet per cve.tools.
EPSS scoreNo EPSS score available; early prediction not yet published.
KEV statusNot in CISA KEV (as of 2026-11-05).
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H — AC:H reflects the narrow preconditions, but C/I/A assume the bypassed account is high-privilege; usually it isn't.
Affected versionsOpenSSH < 10.6p2 on Linux with musl libc and UsePAM no; canonical platform is Alpine Linux openssh-server.
Fixed versionsOpenSSH 10.6p2; Alpine patched packages on supported branches via apk upgrade -U -a.
Scanning/exposure dataIONIX flags SSH services that accept password login as SSH weak auth; no public GreyNoise/Shodan/Censys aggregate for this specific CVE yet.
Disclosure date2026-11-05.
Reporting researcher/orgRich Felker (musl advisory); MITRE CNA; IONIX named SSHHole.

Sources.

  1. CVE Record: CVE-2026-123158
  2. cve.tools CVE-2026-123158
  3. OpenCVE CVE-2026-123158
  4. musl advisory for OpenSSH+musl users
  5. IONIX SSHHole threat center
  6. Security Boulevard SSHhole response
05 · The Call

Final Verdict
↓ DOWNGRADED to MEDIUM (5.5/10)

Why this verdict

  • Friction: musl/no-PAM narrows the install base from all OpenSSH to a minority of Alpine/musl Linux deployments. Baseline 8.1 is fair only for that subset; enterprise glibc/PAM builds are unaffected, so the baseline applies to a niche.
  • Friction: the account precondition further shrinks the vulnerable population. Only accounts whose /etc/shadow password field is * and whose shell is a valid login shell are bypassable. Root is normally blocked by PermitRootLogin prohibit-password, and most service accounts have /sbin/nologin.
  • Role multiplier: no high-value-role floor is triggered. Canonical high-value roles (IdP, AD, CA, PAM, hypervisor, CI/CD, backup, SIEM, edge) overwhelmingly run glibc or FreeBSD and are unaffected; affected OpenSSH-on-musl installs are predominantly Alpine VMs/containers in low/typical roles. If an Alpine edge appliance did have a no-password account, the chain would yield perimeter host compromise, but such installs are well under 1% of the impacted population, so no floor applies.
  • Impact downgrade: CVSS assumes C:H/I:H/A:H (compromised account equals host/domain compromise), but the realistic bypassed account is unprivileged, making the practical impact closer to C:L/I:L/A:L or at most C:H only after a separate local privilege escalation.

Why not higher?

Not higher because the vulnerability requires the intersection of OpenSSH <10.6p2, musl libc, UsePAM no, PasswordAuthentication yes, and an account with a * password hash plus valid shell. That is rare in production. glibc/PAM systems are unaffected, and the default root account is usually shielded by PermitRootLogin prohibit-password.

Why not lower?

Not lower because when those preconditions exist, the attacker gets an unauthenticated remote shell with a single scripted login and no credential guessing. Alpine's default openssh-server is affected in its default configuration if a no-password account exists, and the fix is a standard package upgrade; leaving exposed hosts unpatched creates an easy foothold.

06 · Verification

Crowdsourced verification payload.

Run this bash script on each Alpine/musl Linux host where OpenSSH sshd is installed, as root (needed to read /etc/shadow and run sshd -T). Invocation: bash cve-2026-123158_check.sh. It prints VULNERABLE, PATCHED, or UNKNOWN and exits 0/1/3.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/bin/bash
# CVE-2026-123158 check: OpenSSH <10.6p2 + musl + UsePAM no + PasswordAuthentication yes + no-password account with shell
set -u

SSHD_BIN="$(command -v sshd || true)"
if [ -z "$SSHD_BIN" ] || [ ! -x "$SSHD_BIN" ]; then
  echo "UNKNOWN: sshd not found"
  exit 3
fi

# 1. Check libc
if ! ldd "$SSHD_BIN" 2>/dev/null | grep -q musl; then
  echo "PATCHED: not musl-linked (glibc or non-musl build)"
  exit 0
fi

# 2. Check version < 10.6.2 (OpenSSH_10.6p2)
full_ver="$($SSHD_BIN -V 2>&1 | head -1 | sed -n 's/OpenSSH_\([0-9][^ ,]*\).*/\1/p')"
if [ -z "$full_ver" ]; then
  echo "UNKNOWN: cannot parse sshd version"
  exit 3
fi

if awk -v v="$full_ver" 'BEGIN { split(v,a,"[p.]"); split("10.6.2",b,"[p.]"); for(i=1;i<=3;i++){ if ((a[i]+0) < (b[i]+0)) exit 1; if ((a[i]+0) > (b[i]+0)) exit 0; } exit 0 }'; then
  echo "PATCHED: sshd version $full_ver is >= 10.6.2"
  exit 0
fi

# 3. Check sshd effective configuration
if ! conf="$($SSHD_BIN -T 2>/dev/null)"; then
  echo "UNKNOWN: cannot read sshd effective config (run as root)"
  exit 3
fi

usepam="$(echo "$conf" | awk '$1=="usepam"{print $2}')"
passauth="$(echo "$conf" | awk '$1=="passwordauthentication"{print $2}')"

if [ "$usepam" != "no" ]; then
  echo "PATCHED: UsePAM is '$usepam' (not no)"
  exit 0
fi
if [ "$passauth" != "yes" ]; then
  echo "PATCHED: PasswordAuthentication is '$passauth' (not yes)"
  exit 0
fi

# 4. Look for a locked/no-password account with a valid shell
vuln_account=""
while IFS=: read -r user pass uid gid gecos home shell; do
  if [ "$pass" = "*" ] && [ -n "$shell" ] && ! echo "$shell" | grep -Eq '/(nologin|false)$'; then
    vuln_account="$user"
    break
  fi
done < /etc/shadow

if [ -z "$vuln_account" ]; then
  echo "PATCHED: no locked/no-password account with valid shell found"
  exit 0
fi

echo "VULNERABLE: sshd $full_ver on musl, UsePAM no, PasswordAuthentication yes, account '$vuln_account' has * password with shell $shell"
exit 1