sshole (CVE-2026-123158): OpenSSH Alpine Linux Password Bypass

OpenSSH 10.6p2 patches sshole (CVE-2026-123158, CVSS 8.1), a password bypass on Alpine Linux and musl systems without PAM. Check affected branches and fixes.

William OGOU
15 min read
Share
On this page8 sections

OpenSSH has shipped an emergency release, version 10.6p2, to stop a critical password authentication bypass tracked as CVE-2026-123158 and nicknamed “sshole” (*sshole). Disclosed on November 5, 2026, by researcher Özgün Kültekin of Wakefield, the vulnerability allows an unauthenticated remote attacker to log in to passwordless accounts including SSH key-only users and default cloud accounts by sending any password between 257 and 1,024 bytes in a single connection.

The CVE-2026-123158 flaw affects Linux systems running the OpenSSH daemon (sshd) linked against the musl C standard library (musl libc) with Pluggable Authentication Modules (PAM) disabled. Because that exact combination is the default build for the openssh-server package on Alpine Linux, Alpine maintainers released backported patches on November 5, 2026, covering every release branch from Alpine 3.16 through 3.24 and edge.

Following recent runtime advisories such as PHP2Shell (CVE-2026-109618) and the Node.js Brotli RCE (CVE-2026-111497), sshole demonstrates how subtle edge cases between a daemon and its underlying C library can silently subvert authentication for a decade. This guide breaks down the exact four conditions required for exploitation, how musl and OpenSSH collide on the "*" string, which Alpine packages fix the flaw, and how to patch and hunt for unauthorized logins immediately.

What to Remember

  • The Flaw (CVE-2026-123158): Rated CVSS 3.1 8.1 (High) by MITRE and Critical by the OpenSSH project, sshole (CWE-394) lets a remote attacker authenticate to accounts whose /etc/shadow password field is * by submitting any 257-to-1,024-character password.
  • Narrow Scope (musl + No PAM): The bypass affects OpenSSH before 10.6p2 on Linux systems built with musl libc and running without PAM (most notably Alpine Linux, plus custom OpenWrt, Buildroot, or Yocto builds using openssh-server). Standard glibc distributions (Ubuntu, Debian, RHEL, Fedora), PAM-enabled setups, OpenBSD, and Dropbear SSH are not affected.
  • Four Mandatory Conditions: A server is vulnerable only when it runs sshd on musl without PAM, keeps PasswordAuthentication yes (the default), has at least one account with * in /etc/shadow, and has at least one other local account with a $5$ (SHA-256) or $6$ (SHA-512) password hash.
  • Indirect Root Risk on Cloud Images: While OpenSSH’s default PermitRootLogin prohibit-password blocks direct root password logins, official Alpine tiny-cloud images (3.18.11 through 3.24.3) grant the passwordless alpine account (alpine:*) unrestricted root escalation via doas.
  • Restart Required After Patching: Running apk upgrade -U -a installs the fixed package on disk, but the vulnerable sshd binary remains active in memory until you run rc-service sshd restart.
  • Immediate Workaround: If you cannot upgrade right away, setting PasswordAuthentication no in sshd_config and restarting sshd completely blocks the attack vector.

1. What Is the sshole Vulnerability (CVE-2026-123158)?

In Unix and Linux environments, placing a single asterisk (*) in the password hash field of /etc/shadow designates an account that cannot authenticate with a password. Administrators and image builders routinely use * for SSH key-only deploy accounts, service accounts, directory-backed users (musl-nscd), and the root user on Alpine Linux. Because no valid cryptographic hash outputs a single character, a * entry is supposed to reject every possible password input while still allowing SSH public-key logins when PAM is absent.

Under CVE-2026-123158, that security assumption fails on musl-based OpenSSH servers. When an attacker sends a password exceeding 256 bytes, musl’s crypt() function rejects the input and returns the literal string "*" to indicate an error. Because sshd compares the output of crypt() directly against the stored /etc/shadow field ("*"), the comparison succeeds and logs the attacker in on the first attempt.

AttributeTechnical Detail
CVE IdentifierCVE-2026-123158 (nicknamed sshole / *sshole)
Severity RatingCVSS v3.1: 8.1 (High) (MITRE CNA) / Critical (OpenSSH Project)
Weakness ClassificationCWE-394: Unexpected Status Code or Return Value
Affected SoftwarePortable OpenSSH versions prior to 10.6p2 on Linux with musl libc and no PAM
First Fixed VersionOpenSSH 10.6p2 (released November 5, 2026) and backported Alpine packages
Exploit PayloadAny arbitrary password string between 257 and 1,024 bytes
Discovery & ReportingÖzgün Kültekin (Wakefield), disclosed November 5, 2026
In-the-Wild ExploitationPublic PoCs available; no confirmed in-the-wild exploitation as of November 6

The 4 Conditions Required for Exploitation

According to the official Alpine Linux security advisory, all four of the following prerequisites must be present on a host for CVE-2026-123158 to be exploitable:

  1. sshd Runs on musl Without PAM: The server runs the standard Alpine openssh-server package (which is compiled without PAM support) or runs openssh-server-pam with UsePAM no.
  2. Password Logins Are Enabled: PasswordAuthentication is set to yes in /etc/ssh/sshd_config (which is the default setting in upstream OpenSSH and Alpine’s package).
  3. A Passwordless (*) Target Account Exists: At least one valid account has * as its password field in /etc/shadow (or comes from a directory service via musl-nscd without a shadow entry).
  4. A Real SHA-256 or SHA-512 Hash Exists Elsewhere on the Host: At least one other local account on the machine has a password hash starting with $5$ (SHA-256) or $6$ (SHA-512). One user with a real password is sufficient to expose every * account on the system.

2. How the Overlong Password Bypass Works Under the Hood

The sshole authentication bypass is not a memory-corruption bug or a cryptographic flaw. Instead, CVE-2026-123158 is an architectural collision between three separate engineering decisions made between 2012 and 2022 across musl libc, Portable OpenSSH, and Alpine Linux.

text
┌──────────────────────────────────────────────────────────────────────────────┐
│                  CVE-2026-123158 (*sshole) Execution Flow                    │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  1. Attacker connects to sshd as passwordless user "alice" (/etc/shadow: *)  │
│     and submits a 300-byte password ("AAA...AAA").                           │
│                                    │                                         │
│                                    ▼                                         │
│  2. sshd (built without PAM) calls sys_auth_passwd() -> xcrypt(pw, salt).    │
│     Because alice's stored hash "*" is < 2 chars, it contains no valid salt. │
│                                    │                                         │
│                                    ▼                                         │
│  3. To prevent timing user enumeration (CVE-2016-6210), sshd calls           │
│     pick_salt() and borrows a real "$6$..." salt from local user "bob".      │
│                                    │                                         │
│                                    ▼                                         │
│  4. sshd calls musl's crypt("AAA...AAA", "$6$bob_salt$").                    │
│     musl SHA-512 crypt enforces KEY_MAX = 256 bytes for DoS protection.      │
│                                    │                                         │
│                                    ▼                                         │
│  5. Password length (300) > 256 bytes -> musl crypt() fails and returns      │
│     the literal error token "*" instead of NULL.                             │
│                                    │                                         │
│                                    ▼                                         │
│  6. sshd compares strcmp(encrypted_password, pw_password):                   │
│     strcmp("*", "*") == 0  ──►  AUTHENTICATION ACCEPTED                      │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Three Design Decisions Across a Decade (2012–2022)

Each component behaved according to its own local rationale, but their combination created a deterministic authentication bypass:

  • August 2012 (musl Returns "*" Instead of NULL on Error): POSIX specifies that crypt() should return a NULL pointer when hashing fails. Because many legacy C programs passed the return value of crypt() directly into strcmp() without checking for NULL causing segmentation faults musl commit b3c4cc12 changed crypt() to return a static “unmatchable” string ("*", or "x" if the salt itself started with "*") on failure. Twenty days later, musl commit 88bf5a8a added SHA-256 ($5$) and SHA-512 ($6$) support with a hard 256-byte password limit (#define KEY_MAX 256) to prevent CPU denial-of-service (DoS) attacks. Any password over 256 bytes with a $5$ or $6$ salt therefore causes musl’s crypt() to return "*".
  • July 2016 (OpenSSH Borrows Salts via pick_salt()): To patch CVE-2016-6210 (a timing side-channel that let attackers enumerate valid usernames by measuring whether sshd spent CPU cycles hashing a password), OpenSSH 7.3 (commit 9286875a7) introduced pick_salt() in openbsd-compat/xcrypt.c. Whenever a target account’s password field is too short to contain a valid 2-character salt such as "*" sshd scans the local password database and borrows a $5$ or $6$ salt from another user on the host so crypt() still performs a full SHA-256 or SHA-512 computation. Additionally, OpenSSH 7.3 capped accepted passwords at MAX_PASSWORD_LEN (1,024 bytes), establishing the 257-to-1,024-byte exploit window.
  • 2022 (Alpine 3.16 Switches root:! to root:*): In musl/shadow environments without PAM, prefixing an account hash with ! locks the entire account, blocking SSH public-key logins as well as passwords. In 2022 (commit fbe926af), Alpine 3.16 changed the default root entry from root:! to root:* so administrators could log in via SSH keys without PAM, assuming * would continue to forbid password authentication.

How OpenSSH 10.6p2 Fixes the Flaw

In the OpenSSH 10.6p2 release notes, maintainers state that they consider the root cause to lie outside sshd (in musl’s non-NULL error return), but applied a defensive workaround in sshd (commit 4353fdc43) to make exploitation impossible:

c
/* From OpenSSH 10.6p2 auth-passwd.c (commit 4353fdc43) */
#define MIN_PASSWORD_HASH_LEN	4
#define MAX_PASSWORD_LEN	1024

/* ... inside sys_auth_passwd() ... */
ret = encrypted_password != NULL &&
    strlen(pw_password) >= MIN_PASSWORD_HASH_LEN &&
    strcmp(encrypted_password, pw_password) == 0;
freezero(pw_password, strlen(pw_password));
return ret;

By requiring the stored password hash (pw_password) to be at least 4 characters long (MIN_PASSWORD_HASH_LEN), sshd refuses to match single-character sentinel tokens like "*". The patch also duplicates shadow_pw() strings with xstrdup() rather than holding a pointer into libc’s static getspnam() buffer, and scrubs the buffer with freezero() after comparison.

3. Affected Systems, Cloud Images, and Safe Configurations

Not every Linux server or Alpine container is exposed to CVE-2026-123158. Use the matrix below to triage your fleet rapidly:

Environment / ConfigurationExposure StatusArchitectural Reason
Alpine Linux with default openssh-server + local password userVulnerableUses musl without PAM, defaults to PasswordAuthentication yes, and has a $6$ salt
Alpine tiny-cloud images (3.18.11–3.24.3) once password setCritical Riskalpine:* user has passwordless doas (root); becomes exploitable once any $6$ hash exists
OpenWrt / Buildroot / Yocto (musl) with openssh-serverVulnerableExposed if built without PAM, password auth is enabled, and both * and $5$/$6$ exist
Alpine containers (Docker / Kubernetes) without sshdNot AffectedMost application containers do not run an SSH daemon (see our Docker Hardened Images guide)
Debian, Ubuntu, RHEL, Rocky, Fedora, SUSE (glibc)Not Affectedglibc / libxcrypt returns NULL or "*0" on error, never matching "*"
Servers with PasswordAuthentication no (or cloud-init)Not Affectedsshd rejects password authentication before calling sys_auth_passwd()
openssh-server-pam with UsePAM yesNot AffectedPAM handles authentication instead of sshd’s internal sys_auth_passwd()
Accounts locked with ! in /etc/shadow (user:!:...)Not AffectedLocked accounts are rejected before password hash comparison and never match "*"
OpenWrt default SSH server (Dropbear)Not AffectedDropbear does not use OpenSSH’s pick_salt() / xcrypt() implementation

Why Alpine tiny-cloud Images Face Indirect Root Compromise

On standard Alpine Linux installations, root ships with root:* in /etc/shadow, but OpenSSH’s default PermitRootLogin prohibit-password setting blocks direct password authentication for root (unless an administrator explicitly changed the setting to PermitRootLogin yes).

However, indirect root compromise is a critical risk on official Alpine cloud images built with tiny-cloud (including AWS AMIs, Azure VHDs, and qcow2 artifacts from 3.18.11 through 3.24.3):

  1. Those tiny-cloud images create a default alpine user with * in /etc/shadow and grant alpine passwordless doas privileges (permit nopass :wheel as root).
  2. On first boot, if no account has a password set, no $5$ or $6$ hash exists in /etc/shadow, so pick_salt() falls back to the 2-character DES salt "xx" (which truncates rather than failing at 256 bytes).
  3. As soon as an administrator sets a password for any local account (or user-data provisions a user with hashed_passwd), a $6$ hash is written to /etc/shadow.
  4. An unauthenticated attacker can then log in over SSH as alpine using a 300-character password and immediately execute doas su - to gain full root control.

4. Patched OpenSSH and Alpine Linux Package Versions

Alpine Linux published fixed openssh packages on November 5, 2026, for all active branches (3.22 through 3.24 and edge) as well as end-of-support branches all the way back to Alpine 3.16:

Alpine BranchSupport StatusFirst Fixed openssh PackageFixed Point Release ISO / Cloud Image
edgeRolling development10.6_p2-r0Rolling
3.24Active support10.3_p1-r2Alpine 3.24.4
3.23Active support10.2_p1-r1Alpine 3.23.8
3.22Active support10.0_p1-r11Alpine 3.22.8
3.21End of support (Nov 1, 2026)9.9_p2-r1Alpine 3.21.10
3.20End of support (backported)9.7_p1-r6Upgrade via apk
3.19End of support (backported)9.6_p1-r3Upgrade via apk
3.18End of support (backported)9.3_p2-r4Upgrade via apk
3.17End of support (backported)9.1_p1-r7Upgrade via apk
3.16End of support (backported)9.0_p1-r6Upgrade via apk

If you compile Portable OpenSSH from source on a musl-based distribution (such as custom OpenWrt, Buildroot, or Yocto images), upgrade directly to OpenSSH 10.6p2 or apply commit 4353fdc43.

5. Remediation and Threat Hunting Playbook

Step 1: Audit Exposure and Upgrade OpenSSH

First, verify your installed openssh-server package version and check whether your host meets the exposure conditions. Then update all packages and restart sshd because apk upgrade does not automatically restart the running SSH daemon:

bash
# 1. Check the currently installed openssh package version on Alpine
apk info -v openssh-server

# 2. Check if any accounts have '*' in /etc/shadow alongside a $5$ or $6$ hash
awk -F: '$2 == "*" {print "Passwordless (*) account:", $1} $2 ~ /^\$[56]\$/ {print "SHA-crypt ($5$/$6$) account:", $1}' /etc/shadow

# 3. Upgrade all packages to the patched release and restart sshd
apk upgrade -U -a
rc-service sshd restart

Step 2: Disable Password Authentication (Immediate Workaround)

Enforcing SSH key-only logins aligns with the Principle of Least Privilege and eliminates the sshole attack vector even on unpatched hosts. Before running the commands below, confirm that your SSH key authentication works and keep your current SSH terminal open until you verify a new connection in a separate window:

bash
# 1. Create a drop-in config (read by default on Alpine 3.19+)
mkdir -p /etc/ssh/sshd_config.d
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf

# 2. Force PasswordAuthentication no across /etc/ssh/sshd_config (including Match blocks)
sed -i.bak -e '1i PasswordAuthentication no' \
  -e 's/^\(\s*PasswordAuthentication[^y#]*\)yes/\1no/i' \
  /etc/ssh/sshd_config

# 3. Validate syntax, restart sshd, and confirm effective configuration
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication

Confirm that the final command outputs passwordauthentication no.

Step 3: Hunt for Indicators of Compromise in SSH Logs

Because a successful sshole exploit completes on the first attempt using standard SSH password authentication, it does not generate a burst of failed login alerts. Instead, defenders must look for a successful password login (Accepted password for) on an account that has no password set (*):

bash
# 1. List all accounts currently configured with '*' in /etc/shadow
awk -F: '$2 == "*" {print $1}' /etc/shadow

# 2. Search syslog for any accepted password logins (especially for alpine, root, or key-only users)
grep -E "sshd\[.*\]: Accepted password for" /var/log/messages*

# 3. Audit doas privilege escalations, newly created accounts, and SSH authorized_keys
grep "doas:" /var/log/messages*
find /root /home -name "authorized_keys" -ls 2>/dev/null

If /var/log/messages records Accepted password for an account whose /etc/shadow entry is *, or if log rotation prevents you from ruling out an unauthorized login on an internet-exposed host, treat the machine as compromised, isolate the workload, rotate all credentials and host keys, and rebuild from a patched image (3.21.10, 3.22.8, 3.23.8, or 3.24.4).

Conclusion: Why AI-Driven Bug Discovery Is Shrinking Patch Windows

Beyond the immediate urgency for Alpine Linux administrators, CVE-2026-123158 highlights a broader shift in how decades-old vulnerabilities are being uncovered in 2026. As we analysed in our AI-era CVE exploitation trends report, security researchers are increasingly pairing automated fuzzing harnesses with AI agent swarms to test overlooked integration boundaries. To find sshole, Özgün Kültekin compiled sshd across every permutation of glibc, musl, PAM, and shadow configurations and used agent swarms to fire roughly 17,600 anomalous authentication attempts against the “boring glue code” between OpenSSH and libc.

In the OpenSSH 10.6p2 release announcement, maintainer Damien Miller explicitly noted that the OpenSSH team has seen multiple cases where a bug identified with AI assistance was independently rediscovered by another researcher within hours prompting OpenSSH to abandon long embargoes in favour of immediate single-fix releases. For infrastructure teams, the lesson is unmistakable: patch openssh and restart sshd today, and enforce PasswordAuthentication no across every server so password-handling quirks never reach production.

To further enhance your cloud security and implement Zero Trust, contact me on LinkedIn Profile or [email protected].

FAQ

Frequently Asked Questions (FAQ)

What is the sshole vulnerability (CVE-2026-123158)?

CVE-2026-123158, nicknamed sshole (*sshole), is a high-severity (CVSS 8.1) password authentication bypass in OpenSSH versions prior to 10.6p2. On Linux systems using musl libc without PAM most notably Alpine Linux an attacker can log in to passwordless accounts (marked with * in /etc/shadow) by sending any password between 257 and 1,024 bytes long.

Does CVE-2026-123158 affect Ubuntu, Debian, or RHEL servers?

No. Standard Ubuntu, Debian, Red Hat Enterprise Linux (RHEL), Rocky Linux, and Fedora distributions use glibc (or libxcrypt) and authenticate SSH sessions through PAM. OpenSSH maintainer Damien Miller confirmed that glibc-based Linux systems, PAM-enabled servers, and non-Linux systems are not affected by CVE-2026-123158.

Are Alpine Linux Docker containers vulnerable to sshole?

Most Alpine-based Docker and Kubernetes containers are not affected because they do not install or run the sshd daemon. An Alpine container is vulnerable only if it runs openssh-server without PAM, leaves PasswordAuthentication set to yes, has an account with * in /etc/shadow, and contains at least one other local user with a $5$ or $6$ password hash.

Why does a 257-character password bypass OpenSSH authentication on musl?

When an account has * in /etc/shadow, OpenSSH borrows a $5$ or $6$ salt from another local user to prevent timing-based user enumeration (CVE-2016-6210). However, musl libc rejects passwords longer than 256 bytes for SHA-256 and SHA-512 hashes and returns the string "*" on error instead of NULL. OpenSSH compares that returned "*" against the stored "*" in /etc/shadow and accepts the login.

Can attackers gain root access on Alpine Linux using CVE-2026-123158?

Direct SSH password login as root is blocked by default because PermitRootLogin prohibit-password is enabled unless an administrator changed it to yes. However, on official Alpine tiny-cloud images from 3.18.11 through 3.24.3, an attacker can log in as the passwordless alpine user (once any local account has a $6$ password hash) and escalate to root via passwordless doas.

How do I fix CVE-2026-123158 on Alpine Linux?

Run apk upgrade -U -a to install the patched openssh package for your Alpine branch (such as 10.3_p1-r2 on Alpine 3.24 or 10.6_p2-r0 on edge), and then run rc-service sshd restart so the running daemon reloads the patched binary. If you cannot upgrade immediately, set PasswordAuthentication no in /etc/ssh/sshd_config and restart sshd.

Resources