# OpenSSH CVE-2026-123158 "SSHole": A Long Password Logs In on Alpine. Patch by Nov 12

URL: https://www.devopsness.com/blog/openssh-cve-2026-123158-sshole-alpine-password-bypass
Author: Kiril Urbonas
Published: 2026-11-11
Updated: 2026-11-11
Categories: Linux
Tags: SSH, Security, CVE, Containers, News

Summary: A password-authentication bypass in sshd built without PAM lets a single long password log in to accounts that have no password at all. Alpine is the main target, CISA lists it as exploited, and the federal deadline is November 12. Checks, fixed packages and the one-line stopgap.

---
# OpenSSH CVE-2026-123158 "SSHole": A Long Password Logs In on Alpine. Patch by Nov 12

Upgrade `openssh` on every Alpine host, VM image and container that runs sshd, then restart the daemon. CVE-2026-123158 lets one connection with an overlong password log in to accounts that have no password set, such as key-only users. CISA lists it as exploited, and the federal deadline is November 12. If you cannot patch today, turn off password authentication.

> [!VERIFIED]
> OpenSSH 10.6p2 and the fixed Alpine packages for 3.16 through 3.24 and edge, against the OpenSSH 10.6p2 release notes, the Alpine Linux security post of November 5, 2026, openssh-portable commit 4353fdc and the CISA KEV catalog feed. Checked November 2026.

## What happened, in dates

- **November 5, 2026:** OpenSSH 10.6p2 ships with a fix for "password authentication bypass that is exploitable through sshd(8) that affects some Linux systems when built and run with PAM support disabled." The same day, Alpine publishes its advisory and fixed packages for every branch from 3.16 to edge. The bug was reported by Özgün Kültekin of Wakefield.
- **November 9:** CISA adds CVE-2026-123158 to the Known Exploited Vulnerabilities catalog. The entry asks for forensic triage, lists ransomware use as unknown, and sets a remediation due date of **November 12, 2026**.

OpenSSH says it considers the root cause to be outside sshd, but closes the hole there because sshd is where it can be reached.

## How a long password becomes a login

Without PAM, sshd checks a password itself. It hashes your attempt with `crypt()` using the salt from the account's shadow entry, then compares the result with the stored value. Alpine's advisory spells out how that goes wrong on musl:

1. An account with no password has `*` in its shadow password field. Stock Alpine ships `root:*` (the default `PermitRootLogin prohibit-password` keeps root out), and key-only users, directory-service users without a shadow entry and the `alpine` user in tiny-cloud images are in the same position.
2. `*` is too short to hold a salt, so sshd borrows a salt from another account on the box that has a real `$5$` or `$6$` hash.
3. musl's `crypt()` returns `*` as its error value when the key is longer than 256 bytes.
4. A password of 257 to 1,024 bytes therefore "hashes" to `*`, which matches the stored `*`, and sshd lets the attacker in.

The upstream commit adds a minimum hash-length check before the comparison, so a stored value as short as `*` can no longer match. Glibc systems and anything using PAM do not take this path.

## Am I affected?

You need all four of these at once: sshd without PAM (the `openssh-server` package, or `openssh-server-pam` with `UsePAM no`), password authentication on (the OpenSSH default), at least one account whose password field is `*`, and at least one account with a `$5$` or `$6$` hash.

```bash
# 1. Which sshd build is installed? openssh-server is the non-PAM build.
$ apk info -v 2>/dev/null | grep '^openssh-server'

# 2. What the running config actually allows (needs root)
$ sshd -T | grep -E '^(usepam|passwordauthentication) '

# 3. Accounts with no password, and accounts with real hashes
$ awk -F: '$2 == "*" {print "no-password:", $1}' /etc/shadow
$ awk -F: '$2 ~ /^\$[56]\$/ {print "hashed:", $1}' /etc/shadow

# 4. Kubernetes: which pods are running an sshd process right now?
$ kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{end}' \
  | while read -r ns pod; do
      kubectl exec -n "$ns" "$pod" -- sh -c 'pgrep -x sshd >/dev/null && cat /etc/alpine-release' 2>/dev/null \
        | sed "s|^|$ns/$pod alpine |"
    done

# 5. An image you build or pull: does it ship the non-PAM sshd?
$ docker run --rm --entrypoint sh <image> -c 'cat /etc/alpine-release; apk info -e openssh-server'
```

You are exposed if check 1 shows `openssh-server` (the non-PAM build prints no `usepam` line in check 2) or check 2 shows `usepam no`, check 2 shows `passwordauthentication yes`, and check 3 prints at least one line of each kind. Check 4 is slow on big clusters, so run it per namespace; it only inspects each pod's default container, and only reports it if that container has a shell, `pgrep` and Alpine.

## Fixed Alpine packages, as of November 11, 2026

| Alpine branch | Fixed `openssh` package | Fixed point release |
|---|---|---|
| edge | 10.6_p2-r0 | n/a |
| 3.24 | 10.3_p1-r2 | 3.24.4 |
| 3.23 | 10.2_p1-r1 | 3.23.8 |
| 3.22 | 10.0_p1-r11 | 3.22.8 |
| 3.21 | 9.9_p2-r1 | 3.21.10 (support ended Nov 1) |
| 3.20 | 9.7_p1-r6 | none, unsupported |
| 3.19 | 9.6_p1-r3 | none, unsupported |
| 3.18 | 9.3_p2-r4 | none, unsupported |
| 3.17 | 9.1_p1-r7 | none, unsupported |
| 3.16 | 9.0_p1-r6 | none, unsupported |

Upstream, the fix is OpenSSH 10.6p2. Tiny-cloud VM images (qcow2, VHD, AMI) from 3.18.11 through 3.24.3 are safe at first boot but become exploitable once any account gets a `$6$` password, and their `alpine` user has passwordless `doas`. That makes a hit on that user a root compromise.

## What to do now

**Patch and restart.** Upgrading the package does not replace the daemon that is already running:

```bash
$ apk upgrade -U -a
$ rc-service sshd restart
$ apk info -v openssh-server   # compare with the table above
```

For containers, rebuild on a fixed base (`alpine:3.24.4`, `3.23.8`, `3.22.8` or `3.21.10`) and redeploy. A restart alone pulls nothing new.

**Stopgap: turn off password logins.** Alpine's default `sshd_config` reads drop-in files from 3.19 onward; older releases ignore them, and `Match` blocks in `sshd_config` need editing separately:

```bash
$ mkdir -p /etc/ssh/sshd_config.d
$ echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
$ sshd -T | grep '^passwordauthentication '   # expect: passwordauthentication no
$ sshd -t && rc-service sshd reload
```

Confirm key-based login works in a second session before you close the one you are in. Our [SSH hardening guide](/blog/ssh-hardening-2026-keys-certificates-bastion) covers moving the rest of the fleet to keys and certificates.

## Where this breaks

The stopgap does nothing if another config line later turns password authentication back on, so trust the `sshd -T` output, not the file you edited. Patching does not tell you whether someone already got in. Alpine's advice is to search `/var/log/messages` for `Accepted password for` on accounts that have no password, then review `doas` use, new accounts, new files and `authorized_keys`. If you cannot rule out a login, treat the machine as compromised and rebuild it. Finally, containers that run sshd at all are the bigger problem: an image that needs a debug shell is better served by `kubectl exec` or an ephemeral debug container, and a [distroless base](/blog/distroless-docker-images-smaller-safer) removes the option entirely.

## Questions people ask

### Is Ubuntu or Debian affected by CVE-2026-123158?

Not through this path. The bypass depends on musl's `crypt()` returning `*` for overlong keys, and on sshd running without PAM. Ubuntu and Debian use glibc, build sshd with PAM and ship `UsePAM yes`. Take the update when your distribution ships it, but the emergency is Alpine and other musl systems with PAM off.

### Does disabling root login stop SSHole?

It protects `root` only, and the default `PermitRootLogin prohibit-password` already does that. Any other account with `*` in its password field is still a target: key-only users, directory-service users and the `alpine` user in tiny-cloud images, which can reach root through `doas`. Setting `PasswordAuthentication no` closes the bypass for every account, and patching removes it. Check `/etc/shadow` for `*` entries to see which users are exposed.

### Do I need to restart sshd after apk upgrade?

Yes. `apk upgrade` replaces the binary on disk, but the listening daemon keeps running the old code until it restarts. Run `rc-service sshd restart`, or reboot. In Kubernetes, a pod keeps its image until it is recreated, so rebuild the image on a fixed Alpine release and roll the deployment.

## The call we'd make

Treat any Alpine host or image that runs sshd as exposed until `apk info -v openssh-server` shows the fixed package and the daemon has restarted, and push `PasswordAuthentication no` everywhere today, since it costs nothing on a key-only fleet. The caveat: CISA has evidence of exploitation, so on hosts that were reachable with passwords on, patching is the start of the work, not the end. Check the logs.

## Sources

- [OpenSSH: 10.6p2 release notes](https://www.openssh.org/releasenotes.html)
- [Alpine Linux: openssh-server password authentication bypass](https://alpinelinux.org/posts/2026-11-05-openssh-password-authentication-bypass/)
- [openssh-portable: commit 4353fdc, avoid password authn bypass](https://github.com/openssh/openssh-portable/commit/4353fdc43ef646c43a8dda7025cc1a898caf1482)
- [CISA: Known Exploited Vulnerabilities catalog feed](https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json)

