---
title: "OpenSSH 'sshhole' Bug: Any Long Password Unlocks Locked Alpine Accounts"
url: https://radicalnotion.ai/blog/openssh-sshhole-bug-any-long-password-unlocks-locked-alpine-accounts-20261106000137
type: article
description: "A newly disclosed OpenSSH flaw, CVE-2026-123158 or 'sshhole', lets attackers log into locked accounts on Alpine Linux and other musl-based systems by typing any password longer than 256 characters. Public exploits are already circulating, and fixes shipped within a day of the report."
updated: 2026-11-06
source: RadicalNotion.AI
license: CC BY-NC 4.0 (https://creativecommons.org/licenses/by-nc/4.0/)
---

# OpenSSH 'sshhole' Bug: Any Long Password Unlocks Locked Alpine Accounts

By Radical Notion Team, 2026-11-06

*A newly disclosed OpenSSH flaw, CVE-2026-123158 or 'sshhole', lets attackers log into locked accounts on Alpine Linux and other musl-based systems by typing any password longer than 256 characters. Public exploits are already circulating, and fixes shipped within a day of the report.*

On **Alpine Linux** and other systems that pair **OpenSSH** with the **musl** C library and skip PAM (Pluggable Authentication Modules, the standard Linux login framework), some accounts that administrators believe are locked against password login will accept any password longer than 256 characters. The bug, tracked as **CVE-2026-123158** and nicknamed **"sshhole"** by the researcher who found it, lets a remote, unauthenticated attacker log in without knowing a single real credential. In some common cloud configurations, that leads straight to root. Public proof-of-concept code, reproduction labs and a Google scanner module were all published on **November 5, 2026**, the same day OpenSSH shipped an emergency fix.

---

## What Happened

On November 5, 2026, the OpenSSH project released **OpenSSH 10.6p2**, which its release notes describe as containing a critical security workaround for a password authentication bypass in `sshd`, the SSH server program. MITRE published CVE-2026-123158 that morning (15:46 UTC). The CVE record carries a CVSS 3.1 base score of **8.1 (High)** with the vector `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H`. By 17:12 UTC, CISA's ADP Vulnrichment team had added an SSVC assessment:

- **Exploitation:** `poc` (a public proof-of-concept exists)
- **Automatable:** `no`
- **Technical Impact:** `total`

CISA tagged the researcher's write-up site, **sshhole.com**, as an exploit reference.

OpenSSH credits **Özgün Kültekin of Wakefield** (wakefield.co) with reporting the bug. According to the advisory posted to the `openssh-unix-dev` mailing list, the OpenSSH developers learned of the issue only the day before release, on November 4, 2026. They chose to ship immediately rather than hold the fix under a long embargo, meaning a period of confidential coordination before public disclosure. The team said it now considers long embargoes dangerous because it has recently seen multiple cases of bugs being **rediscovered by AI agents, sometimes within hours**. The advisory also thanked Alpine Linux developers for producing updated packages on very short notice.

OpenSSH developer **Damien Miller** stressed that the project does not consider the root cause to lie within OpenSSH itself. It sits in how the musl C library behaves when password hashing fails. But OpenSSH is "well equipped to avoid it," so the project shipped the workaround. Miller also widened the affected scope beyond the CVE text. OpenSSH builds compiled *with* PAM support (`--with-pam`) are also vulnerable if the running configuration sets `UsePAM no`. He confirmed that **Dropbear SSH**, a lightweight SSH server popular on embedded and Alpine systems, was analyzed and is **not affected**.

The researcher's account on sshhole.com describes how the flaw was found. Kültekin built `sshd` every way they could think of (glibc, musl, PAM, no PAM, shadow, no shadow) and ran roughly **17,600 unusual login attempts** against each build using automated agent swarms. The test cases included odd hashes, broken accounts and absurdly long passwords. In their words: *"every build agreed on every login. except musl without pam. that one said yes to things it shouldn't."*

---

## Understanding the Vulnerability

This bug has no memory corruption and no clever shellcode. It comes from three reasonable decisions, made years apart by different projects, that happen to line up.

### Piece 1: The asterisk that means "locked"

On Unix-like systems, an account's password hash lives in `/etc/shadow`. A hash is a one-way scrambled version of the password. When the password field holds a value that can never be a real hash, such as a single asterisk (`*`), password login is disabled for that account. Depending on configuration, the user can still log in with an SSH key. According to sshhole.com, this convention goes back to **1980**, when Bill Joy used `*` for the daemon account in 3BSD's `/etc/passwd`.

Alpine Linux leans on this convention:

- Alpine's fix for an earlier flaw, **CVE-2019-5021**, locked the root account with `!`.
- Without PAM, `!` also blocked SSH *key* logins.
- So in **2022, Alpine 3.16 switched root's shadow field to** `*`, which kept the root password locked but made key logins work again.

The Alpine advisory adds that accounts such as the default `alpine` user in Alpine's **tiny-cloud** images, key-only users, and users retrieved through **musl-nscd** (a service that lets musl systems look up users from external directories) can also carry a `*` password field.

### Piece 2: musl's `crypt()` answers failure with `"*"`

`crypt()` is the standard C function that turns a password plus a "salt" into a hash. The salt is a random value stored with the hash, such as `$6$abc123...`, where `$5$` means SHA-256 and `$6$` means SHA-512. Traditionally, `crypt()` returns `NULL` when it fails, and many programs crashed because they never checked for that.

According to sshhole.com:

- **August 2012, musl commit** `b3c4cc12`**:** musl changed `crypt()` to return the string `"*"` on failure instead of `NULL`, so careless callers would no longer crash.
- **Three weeks later, musl commit** `88bf5a8a`**:** musl added SHA-512 crypt with a **256-byte cap on password length**. SHA-512 crypt gets slower as the password gets longer, so an attacker could tie up a server with one giant password. Inputs longer than 256 bytes are rejected.

The researcher summed up the combination: *"so past 256 bytes crypt fails. and when crypt fails... it says* *"*"."\*

glibc systems that use **libxcrypt** avoid the trap because libxcrypt signals failure with `NULL` or `*0`, which can never equal a lone `*`. sshhole.com notes that this was a near miss. In 2013, **Debian bug #714219** considered copying musl's `*` behavior into glibc before Debian moved to libxcrypt. In **December 2024**, a thread on the musl mailing list noted that BusyBox `passwd` failed on 257-character passwords for exactly this reason (the 256-byte limit plus the `*` return value), but nobody connected it to `sshd`.

### Piece 3: OpenSSH hashes *something* even for locked accounts

In 2016, OpenSSH fixed **CVE-2016-6210**, a timing attack that let attackers tell which usernames existed by measuring how quickly the server rejected passwords. The fix makes `sshd` run the full password hash even for nonexistent users and for accounts whose stored field is too short to hold a salt, such as `*`. To do that, `sshd` **borrows a salt from another account on the system** that has a real hash.

The Alpine advisory spells out the consequence. If at least one other local account has a `$5$` (SHA-256) or `$6$` (SHA-512) hash, `sshd` uses that salt. musl then runs its SHA-based crypt, which enforces the 256-byte cap.

### Putting it together

Without PAM, `sshd` checks a password by hashing the attempt with `crypt()` and comparing the result to the stored field. For a locked `*` account and a long password, the sequence is:

1. The stored field is `*`, which is too short to contain a salt.
2. `sshd` borrows a `$6$` (or `$5$`) salt from another account.
3. The attacker's password exceeds 256 bytes, so musl's `crypt()` fails and returns `"*"`.
4. `sshd` compares `"*"` (the error marker) with `"*"` (the stored lock marker).
5. The strings match, so **authentication succeeds**.

PAM-based configurations avoid this because, per sshhole.com, PAM never calls `crypt()` for a `*` account in the first place. The researcher also explained why nobody caught it: \*"openssh tests on openbsd and glibc, musl doesn't test sshd, and most distros go through pam, which never even calls crypt for a *."*

The CVE classifies the flaw as **CWE-394: Unexpected Status Code or Return Value**. That fits: `sshd` read an error value as if it were a real password hash.

The following simplified sketch shows the logic flaw. It is *illustrative only, not verbatim OpenSSH source*:

```plaintext
/* Simplified illustration of pre-10.6p2 non-PAM password checking.
 * NOT verbatim OpenSSH code. */
char *pw_password = shadow_pw(pw);     /* "*" for a locked / key-only account */

/* Stored field too short to hold a salt, so xcrypt() borrows one from
 * another account (e.g. "$6$...") as CVE-2016-6210 timing protection. */
char *encrypted = xcrypt(password, pw_password);

/* On musl, a password > 256 bytes makes SHA-crypt fail and
 * crypt() returns the literal string "*" instead of NULL. */

return encrypted != NULL &&
       strcmp(encrypted, pw_password) == 0;   /* "*" == "*" -> SUCCESS */
```

### The fix in 10.6p2

The upstream commit (`4353fdc43ef646c43a8dda7025cc1a898caf1482` in `openssh-portable`) adds a minimum length for stored password hashes, `MIN_PASSWORD_HASH_LEN 4`. `sshd` now requires `strlen(pw_password) >= MIN_PASSWORD_HASH_LEN` before it compares anything, so a one-character stored field like `*` can never authenticate. The commit touches `auth-passwd.c`, `openbsd-compat/xcrypt.c` and `openbsd-compat/port-uw.c`. It also fixes how strings returned by `shadow_pw()` are handled, so the caller now owns and frees them. The following sketch is illustrative:

```plaintext
/* Illustrative sketch of the 10.6p2 workaround (see upstream commit
 * 4353fdc43ef646c43a8dda7025cc1a898caf1482 for the exact change). */
#define MIN_PASSWORD_HASH_LEN 4

/* A stored "hash" shorter than this cannot be a real hash
 * ("*", "!", "x", etc.), so it must never match a crypt() result. */
if (strlen(pw_password) < MIN_PASSWORD_HASH_LEN)
        return 0;                          /* fail closed */

encrypted = xcrypt(password, pw_password);
return encrypted != NULL && strcmp(encrypted, pw_password) == 0;
```

### What an attacker needs

All of the following conditions must hold:

- **OpenSSH earlier than 10.6p2** on **Linux**.
- `sshd` **linked against musl libc**.
- **No PAM.** Either the build lacks PAM support, or it was built `--with-pam` but runs with `UsePAM no`. On Alpine, that means the `openssh-server` package, or `openssh-server-pam` configured with `UsePAM no`.
- `PasswordAuthentication` **enabled**.
- A **target account whose stored password field is** `*`.
- **At least one other local account with a** `$5$` **or** `$6$` **hash** for `sshd` to borrow a salt from, per the Alpine advisory.
- A password **longer than 256 bytes**:
- **For root:** `PermitRootLogin yes`. OpenSSH's default, `prohibit-password`, blocks root password logins.

These preconditions explain the CVSS "Attack Complexity: High" rating. Once they are met, however, the attack itself is trivial. The Alpine advisory rates exploitability as **easy**, and sshhole.com describes the login bypass as low-complexity.

### The attack chain, step by step

Combining the Alpine advisory, sshhole.com and the two public reproduction labs:

1. **Reconnaissance.** Find an `sshd` that accepts password authentication and runs on a musl-based system without PAM, such as a default Alpine host or an Alpine tiny-cloud image.
2. **Pick a target account** whose shadow field is `*`. Candidates include the tiny-cloud default `alpine` user, root if `PermitRootLogin yes`, key-only users, or musl-nscd users.
3. **Confirm a salt donor exists.** At least one other local account needs a `$5$` or `$6$` hash.
4. **Connect with password authentication forced** and public-key authentication disabled.
5. **Send an overlong password.** The public reproductions send *two* password attempts in the same SSH connection:
6. **musl's** `crypt()` **fails** on the oversized input and returns `*`.
7. `sshd` **compares** `*` **to** `*`, gets a match, and opens a session as the target user.
8. **Escalate if possible.** If the account is root, or is the tiny-cloud `alpine` user with **passwordless** `doas` (Alpine's lightweight `sudo` equivalent), the attacker now controls the whole machine.

### Public proof-of-concept labs

Two GitHub repositories provide disposable Docker environments for confirming the issue and testing defenses. **Run them only against systems you own.**

From `leonjza/sshhole-lab`, the published commands are:

```bash
# Start the vulnerable lab container (Alpine + vulnerable OpenSSH)
docker run --rm -it -p 2222:22 ghcr.io/leonjza/sshhole-lab:latest

# In another terminal, connect forcing password authentication
ssh -o StrictHostKeyChecking=no \
    -o PreferredAuthentications=password \
    -o PubkeyAuthentication=no \
    -p 2222 alpine@localhost

# When prompted, enter any password longer than 256 characters - twice.
```

The `predkambrij/sshhole-repro` project is a self-contained Docker PoC. According to its analysis, it:

- builds an **Alpine 3.15** container with vulnerable OpenSSH;
- creates a locked account with `*` in `/etc/shadow`;
- enables password authentication;
- uses `SSH_ASKPASS` (with `SSH_ASKPASS_REQUIRE=force`, which requires an **OpenSSH client 8.4 or newer**) to feed two password attempts in one connection: a first attempt that primes the cached fake salt, then **300** `A` **characters**.

It includes both non-root and root variants. The root variant also sets `PermitRootLogin yes`. The client options it relies on look like this:

```bash
# Client-side options used by the repro to force two password attempts
# in a single connection (lab use only)
ssh -o PubkeyAuthentication=no \
    -o PreferredAuthentications=password \
    -o NumberOfPasswordPrompts=2 \
    -p <lab-port> <locked-user>@<lab-host>

# The second password supplied is an overlong string, e.g.:
python3 -c 'print("A" * 300)'
```

Google's open-source **goonami-scanner** gained detection through **pull request #277**. That PR maps its `opensshauthbypass` detector to CVE-2026-123158.

---

## Who Is Affected

**Upstream OpenSSH**

| Vendor | Product | Affected Versions | Fixed Versions |
| --- | --- | --- | --- |
| OpenBSD | OpenSSH (Portable) | All versions before 10.6p2, on Linux with musl libc and no PAM (or `UsePAM no`) | 10.6p2 (commit `4353fdc43ef646c43a8dda7025cc1a898caf1482`) |

**Alpine Linux** `openssh-server` **packages** (from the Alpine advisory)

| Alpine Branch | Affected | Fixed Package | Included In |
| --- | --- | --- | --- |
| edge | \< 10.6\_p2-r0 | 10.6\_p2-r0 | n/a |
| 3.24 | \< 10.3\_p1-r2 | 10.3\_p1-r2 | Alpine 3.24.4 |
| 3.23 | \< 10.2\_p1-r1 | 10.2\_p1-r1 | Alpine 3.23.8 |
| 3.22 | \< 10.0\_p1-r11 | 10.0\_p1-r11 | Alpine 3.22.8 |
| 3.21 | \< 9.9\_p2-r1 | 9.9\_p2-r1 | Alpine 3.21.10 |
| 3.20 | \< 9.7\_p1-r6 | 9.7\_p1-r6 | n/a |
| 3.19 | \< 9.6\_p1-r3 | 9.6\_p1-r3 | n/a |
| 3.18 | \< 9.3\_p2-r4 | 9.3\_p2-r4 | n/a |
| 3.17 | \< 9.1\_p1-r7 | 9.1\_p1-r7 | n/a |
| 3.16 | \< 9.0\_p1-r6 | 9.0\_p1-r6 | n/a |

**Other Alpine components**

| Vendor | Product | Affected | Fix / Mitigation |
| --- | --- | --- | --- |
| Alpine Linux | `openssh-server-pam` | Same branch ranges as above **when configured with** `UsePAM no` | Same fixed versions; switching to `UsePAM yes` also mitigates |
| Alpine Linux | tiny-cloud images | 3.18.11 through 3.24.3 | Updated images and patched packages (Alpine did not list exact fixed image versions) |

The `leonjza/sshhole-lab` analysis independently confirmed that Alpine Linux **3.24.1**'s package `10.3_p1-r1` is vulnerable.

**Not affected**, per OpenSSH and Damien Miller:

- non-Linux systems, including OpenBSD;
- Linux systems using glibc;
- Linux systems where PAM handles password authentication;
- Dropbear SSH.

The CNA record's `defaultStatus` is "unaffected."

**A scanner warning.** The CPE in the CVE record, `cpe:2.3:a:openbsd:openssh:*:*:*:*:*:*:*:*` with `versionEndExcluding 10.6p2`, cannot express the musl and no-PAM conditions. Expect version-based scanners to flag nearly every OpenSSH install older than 10.6p2, including glibc servers that are not vulnerable. Confirm the libc and PAM configuration before you treat a finding as real.

The affected population is narrower than "all of OpenSSH," but it matters. Alpine is one of the most widely used base images in containers, a favorite for minimal cloud VMs, and common on appliances and edge devices. The intelligence gaps flagged across sources include whether other musl-based distributions ship OpenSSH without PAM in a vulnerable way. If you run any musl-based system, check it yourself rather than assuming Alpine is the only case.

---

## Real-World Risk

As of publication, **none of the sources report confirmed in-the-wild exploitation**, and no threat actor or campaign has been tied to this bug. CISA's SSVC rating is `poc`, not `active`.

That status may not last. The usual gap between disclosure and weaponization did not exist here. The vulnerability, a detailed root-cause write-up, two turnkey Docker labs and a scanner module all became public on the same day. The "exploit" is an SSH client and a long string, so anyone who can type can use it. CISA rates it non-automatable because of the per-host preconditions, not because the attack is hard.

The most dangerous scenarios in the reference material:

- **Alpine tiny-cloud images (3.18.11 through 3.24.3).** The Alpine advisory warns that the default `alpine` user has a `*` password field and **passwordless** `doas`. If first-boot or user-data provisioning creates *any* other user with a `$6$` password hash, the `alpine` user becomes remotely accessible with any 257-to-1024-byte password, and passwordless `doas` makes that **instant root**. Alpine recommends hardening provisioning so it does not create a single user with a `$6$` hash.
- **Root on Alpine 3.16 and later.** Root's shadow field has been `*` since 2022. Any host that combines a vulnerable `sshd`, `PermitRootLogin yes`, password authentication, and at least one other user with a real password hash is open to unauthenticated remote root.
- **Key-only service and admin accounts.** Administrators deliberately set these to `*` precisely *because* they are meant to be key-only, so the accounts people consider most locked down are the exposed ones.

Once inside, an attacker can do whatever the compromised account can do. The impact assessments list data theft, malware and persistence, new user accounts or `authorized_keys` entries, lateral movement, theft of cloud metadata and user-data secrets, container-escape attempts from privileged workloads, and service disruption.

**The logs won't flag it.** A successful bypass appears in the logs as an ordinary `Accepted password for <user> from <ip>` line. The Damien Miller analysis notes that **password length is not logged**, so defenders have to spot these events by context, such as a password login to an account that has no password.

---

## What You Should Do

### 1. Immediate triage: find exposed hosts

On each Linux host running `sshd`, check four things.

```bash
# 1. Is sshd linked against musl?
ldd "$(command -v sshd)" 2>/dev/null | grep -i musl

# 2. What is the effective config? (password auth, PAM, root login)
sshd -T 2>/dev/null | grep -Ei '^(passwordauthentication|usepam|permitrootlogin) '

# 3. Which accounts are locked with a bare '*'? (potential targets)
awk -F: '$2 == "*" {print $1}' /etc/shadow

# 4. Which accounts have SHA-256/SHA-512 hashes? (potential salt donors)
awk -F: '$2 ~ /^[$][56][$]/ {print $1}' /etc/shadow
```

A host with musl, `passwordauthentication yes`, `usepam no` (or no PAM at all), at least one `*` account, and at least one `$5$` or `$6$` account is in the danger zone. To scan at scale, use the **goonami-scanner** `opensshauthbypass` **detector** (PR #277).

### 2. Patch, then restart sshd

- **Upstream builds:** upgrade to **OpenSSH 10.6p2** or later.
- **Alpine Linux:** upgrade to the fixed `openssh` package for your branch, using the table above:

```bash
apk update
apk upgrade openssh-server openssh-server-pam openssh

# CRITICAL: upgrading the package does NOT replace the running daemon
rc-service sshd restart
```

The Alpine advisory stresses that **upgrading the package does not replace the running** `sshd` **process**. Until you restart the daemon, the vulnerable code keeps running. For containers and cloud images, rebuild on patched base images and redeploy rather than patching running instances in place. Tiny-cloud users should move to updated images.

### 3. Workarounds if you cannot patch right now

OpenSSH's own advisory recommends, as an emergency step, setting `PasswordAuthentication=no` immediately or **disabling SSH entirely** on affected systems until they are patched. In order of preference:

- **Disable password authentication** (full mitigation; key-based logins keep working). Add a drop-in file and restart:

```bash
printf 'PasswordAuthentication no\n' > /etc/ssh/sshd_config.d/00-cve-2026-123158.conf
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication   # should print: passwordauthentication no
```

- **Switch to PAM** (full mitigation). On Alpine, install `openssh-server-pam` and set `UsePAM yes`. PAM never calls `crypt()` for `*` accounts. Test this first, because it changes your authentication stack.
- **Lock unused accounts with** `!` **instead of** `*` (full mitigation for those accounts, per Alpine). The Alpine advisory notes that `user:!:` accounts cannot log in with a password *or* a key. Don't apply this to accounts that need SSH keys, which is the exact reason Alpine moved root to `*` in 3.16. sshhole.com also suggests other lock markers such as `!*`, but only after you validate the behavior yourself.
- **Remove every** `$5$` **and** `$6$` **hash from local accounts** (full mitigation, per Alpine). Without a salt donor, the bypass fails. This is rarely practical, because it eliminates local password logins entirely.
- **Keep** `PermitRootLogin` **at** `prohibit-password` **(the default) or** `no`**.** This protects root only; other `*` accounts stay exposed.
- **Restrict network access to** `sshd` with firewalls, allowlists, VPN or bastion hosts. This reduces exposure but does not fix the bug.

### 4. Hunt for compromise

Treat any host that ran a vulnerable configuration while reachable from untrusted networks as potentially compromised. Alpine logs to `/var/log/messages` by default; other systems may use `/var/log/auth.log` or `journalctl`.

```bash
# Look for password logins at all, then flag ones for '*' / key-only accounts
grep 'Accepted password for' /var/log/messages /var/log/auth.log 2>/dev/null

# Cross-reference against accounts that have no real password
for u in $(awk -F: '$2 == "*" {print $1}' /etc/shadow); do
  grep -h "Accepted password for $u " /var/log/messages /var/log/auth.log 2>/dev/null
done
```

Red flags to look for:

- `Accepted password for` entries for `root`, `alpine`, key-only users, or any account whose shadow field is `*`. **On an unaffected system, these accounts should never authenticate by password.**
- A failed password attempt followed by a success for the same account and source within one connection. This matches the two-attempt pattern in the public reproductions.
- Successful password logins from IP addresses with no prior history, especially after November 5, 2026.
- Unexpected `doas` or `sudo` activity from accounts that normally never log in interactively.
- New user accounts, new or modified `~/.ssh/authorized_keys` files, and unfamiliar files or cron jobs.
- In packet captures or debug logs, password authentication attempts between 257 and 1024 bytes long.

No official Sigma, YARA or IDS signatures were published with the disclosure. A simple SIEM rule (alert on any successful SSH password authentication for a user whose shadow field is `*`, especially root, on a musl host) covers the core signal.

### 5. Clean up

If you find signs of compromise:

- rotate credentials and SSH keys on the affected systems;
- treat secrets reachable from them as exposed, including cloud metadata credentials, tiny-cloud user-data and application secrets;
- re-enable password authentication only after confirming that the patched `sshd` is the one actually running.

### Timeline

| Date | Event |
| --- | --- |
| 1980 | Bill Joy introduces `*` for the daemon account in 3BSD `/etc/passwd` |
| Aug 2012 | musl commit `b3c4cc12`: `crypt()` returns `"*"` on failure instead of `NULL` |
| Aug 2012 (three weeks later) | musl commit `88bf5a8a`: SHA-512 crypt with a 256-byte password cap |
| 2013 | Debian bug #714219 weighs copying musl's `*` behavior into glibc; Debian later adopts libxcrypt (`*0`) |
| 2016 | OpenSSH fixes CVE-2016-6210 by hashing invalid and `*` users with a borrowed salt |
| 2022 | Alpine 3.16 switches root's shadow field from `!` to `*` |
| Dec 2024 | musl list thread notes BusyBox `passwd` fails on 257-char passwords; `sshd` impact missed |
| Nov 2026 | Özgün Kültekin (Wakefield) finds the bug through ~17,600-login differential testing |
| Nov 4, 2026 | OpenSSH developers learn of the issue |
| Nov 5, 2026 | OpenSSH 10.6p2 released; Alpine ships fixed packages; CVE-2026-123158 published (15:46 UTC); CISA SSVC added (17:12 UTC); PoCs, labs and scanner published |

---

## The Bigger Picture

The flaw comes from four safety decisions, each sensible on its own:

- a 1980 convention for marking accounts locked;
- a 2012 choice to keep careless programs from crashing;
- a 2012 cap meant to prevent denial-of-service;
- a 2016 timing-attack fix in OpenSSH.

Together they formed a remote root hole that sat in plain sight for years, and one dropped mailing-list thread in 2024 nearly exposed it. Nobody wrote an obviously wrong line of code. The failure came from projects making different assumptions about what a function's return value means. That is CWE-394 at its purest, and it is a reminder that code returning a sentinel value instead of a clear error can end up matching real data.

A few lessons stand out for defenders:

- **Configuration matters as much as version.** Most of the OpenSSH world is not vulnerable to this bug. The musl, no-PAM, `*`-account combination is. Asset inventories that record only package versions will get this one wrong in both directions.
- **Minimal builds have untested paths.** Alpine's appeal is that it strips things out, including PAM. As the researcher noted, the musl-without-PAM path simply wasn't tested against `sshd`. Every "we don't need that" decision creates a less-traveled code path.
- **Password authentication on internet-facing SSH is a liability.** Every effective mitigation here comes back to one question: why is password auth enabled at all? If you don't need it, turn it off. This bug is a good reason to do so.
- **Disclosure timelines are shrinking.** OpenSSH shipped a fix about a day after learning of the bug, explicitly because AI agents are rediscovering bugs within hours. The flaw itself was found by agent-driven differential testing at a scale (about 17,600 login variations across many builds) that no human tester would attempt. Expect more vulnerabilities to surface this way, with less advance warning and public exploits arriving the same day as the patch. Patch cycles measured in weeks are now too slow.

Watch for:

- updated Alpine tiny-cloud images with exact fixed version numbers;
- advisories from other musl-based distributions;
- whether CISA's SSVC exploitation rating moves from `poc` to `active`;
- detection content (Sigma rules, IDS signatures) from the security community.

In the meantime, the practical rule for Alpine and other musl-based hosts is simple: an account locked with `*` should never log in with a password, so investigate any log entry showing that it did.

## Sources

- [NVD - CVE-2026-123158](https://nvd.nist.gov/vuln/detail/CVE-2026-123158)
- [OpenSSH 10.6p2 Release Notes (Vendor Advisory)](https://www.openssh.org/releasenotes.html#10.6p2)
- [OpenSSH Portable Fix Commit 4353fdc](https://github.com/openssh/openssh-portable/commit/4353fdc43ef646c43a8dda7025cc1a898caf1482)
- [OpenSSH Security Advisory - openssh-unix-dev Mailing List](https://marc.info/?l=openssh-unix-dev&m=179388064263131&w=2)
- [Damien Miller (OpenSSH) Statement on Hachyderm](https://hachyderm.io/@damienmiller/117563026759098135)
- [Alpine Linux Advisory - OpenSSH Password Authentication Bypass](https://alpinelinux.org/posts/2026-11-05-openssh-password-authentication-bypass/)
- [sshhole.com - Researcher Write-up and Exploit Details](https://sshhole.com)
- [predkambrij/sshhole-repro - Docker PoC Reproduction](https://github.com/predkambrij/sshhole-repro)
- [leonjza/sshhole-lab - Vulnerable Lab Environment](https://github.com/leonjza/sshhole-lab)
- [Google goonami-scanner PR #277 - opensshauthbypass Detector](https://github.com/google/goonami-scanner/pull/277)
- [Hacker News Discussion (item 50377976)](https://news.ycombinator.com/item?id=50377976)
- [Hacker News Discussion (item 50378228)](https://news.ycombinator.com/item?id=50378228)
- [Hacker News Discussion (item 50379704)](https://news.ycombinator.com/item?id=50379704)

Tags: CVE-2026-123158, OpenSSH, Alpine Linux, authentication-bypass, musl-libc

---

Source: [RadicalNotion.AI](https://radicalnotion.ai/blog/openssh-sshhole-bug-any-long-password-unlocks-locked-alpine-accounts-20261106000137). Licensed CC BY-NC 4.0; attribute RadicalNotion.AI and link the source page when you reuse this data.
