SSHole (CVE-2026-123158): Check Alpine and Docker Images for the OpenSSH Password Bypass

Based on the official docs for OpenSSH 10.6p2 and Alpine's patched openssh packages (November 2026) Hardware test not run How guides are made and checked

SSHole (CVE-2026-123158) lets someone log in over SSH without knowing the password on certain Linux systems built on musl libc, most notably Alpine Linux. It is being exploited, and CISA added it to its Known Exploited Vulnerabilities catalogue on 9 November 2026. If you run small Alpine VMs, a Raspberry Pi with a musl distro, or Docker containers that run sshd, this guide shows you how to check each one, patch it, and close the gap for good.

This is a defensive guide: only run these checks on servers and containers you own or have written permission to test.

The short version: update the openssh-server package, restart sshd, and set PasswordAuthentication no.

What SSHole is, in plain words

On musl-based systems, the C library’s crypt() function returns the string * when it gets a password that is too long (more than 256 bytes). On Alpine, * is also what /etc/shadow stores for accounts that have no password, such as root in the base image or key-only users. Without PAM in the way, sshd compared the two, saw a match, and let the login through. glibc returns NULL in the same situation, which sshd already rejects, so Debian, Ubuntu, Fedora and RHEL are not affected.

The OpenSSH team shipped a workaround in Portable OpenSSH 10.6p2 on 5 November 2026. In their words, “the root cause of this bug [is] outside sshd, but it is exploitable via sshd and can be avoided there.” The bug was reported by Özgün Kültekin, and researchers trace the behaviour back to a 2016 change. It is rated CVSS 3.1 8.1 (High).

Are you affected?

A server or container is exploitable only when all of these are true (this is the list Alpine published and the research write-ups repeat):

  1. sshd runs on Linux with musl libc and is built without PAM, or with UsePAM no. Alpine’s stock openssh-server package is this build.
  2. PasswordAuthentication is on. It is on by default.
  3. At least one account has a password field of exactly *. Locked accounts (!) are safe.
  4. At least one other account has a real $5$ or $6$ password hash, because the attack borrows its salt.

Not affected: glibc distros, systems that use PAM with UsePAM yes, Dropbear (for example OpenWrt’s default SSH server), and any server with PasswordAuthentication no. Synology says its DSM, SRM, BeeStation and APM releases are not affected.

Two Alpine details make this worse than it looks. Alpine’s root account has used * for years, but the default PermitRootLogin prohibit-password blocks a direct root login. The bigger risk is Alpine’s cloud images (tiny-cloud, versions 3.18.11 to 3.24.3), which ship an alpine user with * and passwordless doas. If any other account on the box has a password, an attacker can log in as alpine and become root.

What you need

  • Shell access (as root, or with doas or sudo) to each Alpine host.
  • Docker CLI access on any host that runs containers.
  • A second SSH session kept open while you change sshd settings, so a mistake doesn’t lock you out.

Step 1: Check an Alpine host

First, see which OpenSSH package is installed and whether sshd uses musl:

apk list --installed | grep '^openssh-server'
ldd /usr/sbin/sshd | head -1

If ldd shows ld-musl, the build is musl. Now check the settings sshd is actually using, and look for the two kinds of accounts the attack needs:

sshd -T | grep -iE 'usepam|passwordauthentication|permitrootlogin'
awk -F: '$2=="*"{print $1}' /etc/shadow
awk -F: '$2 ~ /^\$[56]\$/{print $1}' /etc/shadow

sshd -T needs root. If both awk commands print account names and passwordauthentication yes is set on a build from before the fix, the host was exploitable.

One catch: plain sshd -T ignores Match blocks. If you use them, test the real connection details, for example sshd -T -C user=alpine,host=example,addr=203.0.113.10.

Is my package the fixed one?

Don’t trust the version banner. Alpine backported the fix into its existing package versions, so ssh -V can still show an older OpenSSH number on a patched host. Check the package revision instead. These are the fixed packages Alpine lists for each branch:

Alpine branchFixed openssh package
edge10.6_p2-r0
3.2410.3_p1-r2
3.2310.2_p1-r1
3.2210.0_p1-r11
3.219.9_p2-r1
3.209.7_p1-r6
3.199.6_p1-r3
3.189.3_p2-r4
3.179.1_p1-r7
3.169.0_p1-r6

Your installed version must be the same or newer than the one for your branch (run cat /etc/alpine-release if you’re not sure which branch you’re on). This also means vulnerability scanners that only compare against “10.6p2” may flag patched Alpine hosts, so check the revision before you panic.

Step 2: Patch the host and restart sshd

apk update
apk upgrade openssh openssh-server
rc-service sshd restart

The restart matters. Upgrading the package does not replace the sshd process that is already running, so the old code keeps answering connections until you restart it. Run the apk list command from Step 1 again to confirm the new revision.

You can use apk upgrade -U -a to update everything, but note that -a can also downgrade packages you’ve pinned to a different repository, so upgrading just the OpenSSH packages is the safer choice on a box you haven’t looked at in a while.

Step 3: Turn off password logins

Even after patching, key-only SSH is the better setup. Keep your second session open, then:

echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication

The last line should print passwordauthentication no. The 00- prefix makes the file load first, and in sshd the first value set wins. The sshd_config.d drop-in folder works on Alpine 3.19 and later; on older releases, edit /etc/ssh/sshd_config directly. If you haven’t set up keys yet, follow our passwordless SSH guide before you do this.

This setting on its own also blocks SSHole, so it is your stopgap if you can’t patch straight away.

Step 4: Check your Docker containers

Most Alpine-based images are fine, because they don’t run sshd at all. The risk is containers that do: SSH jump boxes, dev containers, “VM in a container” images, and some CI images.

List the running containers that have the OpenSSH server package installed:

for c in $(docker ps --format '{{.Names}}'); do
  v=$(docker exec "$c" sh -c 'apk info -v 2>/dev/null | grep "^openssh-server"' 2>/dev/null)
  [ -n "$v" ] && echo "$c: $v"
done

Each line shows a container name and its package version, for example jumpbox: openssh-server-10.0_p1-r10. Compare it with the table above. For any container in the list, check the accounts and settings inside it (as root):

docker exec -u 0 jumpbox sh -c "awk -F: '\$2==\"*\"{print \$1}' /etc/shadow; sshd -T | grep -i passwordauth"

To check an image before you run it:

docker run --rm --entrypoint /bin/sh IMAGE -c 'cat /etc/alpine-release; apk info -v 2>/dev/null | grep "^openssh-server"'

Having the package installed doesn’t prove the image runs sshd, so also check what it starts with docker inspect --format '{{.Config.Entrypoint}} {{.Config.Cmd}}' IMAGE.

Fixing a container

The proper fix is to rebuild or pull a new image. If you build your own, rebuild with a fresh base so you pick up the patched package:

docker build --pull --no-cache -t myimage .
docker compose up -d

If you use a published image such as linuxserver/openssh-server (which is Alpine-based), pull the latest tag and recreate the container with docker compose pull and docker compose up -d, then run the check loop again to confirm the package revision. Its docs show PASSWORD_ACCESS=false in the examples; leave it that way unless you really need passwords.

As a short-term stopgap you can patch in place with docker exec -u 0 <container> apk upgrade -U openssh openssh-server and then docker restart <container>. That survives a restart but is lost the moment the container is recreated from the old image, so treat it as a bridge to a rebuild, not the fix. If you run Docker on Alpine yourself, our Docker on Alpine guide covers the basics.

Step 5: Look for signs someone got in

Because this was exploited within hours of disclosure, check the logs on any host that was exposed. Look for successful password logins to accounts that have no password:

grep sshd /var/log/messages | grep 'Accepted password for'

An Accepted password line for alpine, root or a key-only service account is a red flag. Also review recent doas use, new users, new entries in ~/.ssh/authorized_keys, and changed files. Alpine’s advice is that if you can’t rule out a login, treat the host as compromised and rebuild it.

What’s changed recently

  • 5 November 2026: OpenSSH 10.6p2 and Alpine’s patched packages released, the same day the CVE was published. The OpenSSH team says it will now ship fixes more often rather than batching them.
  • 5 to 8 November: honeypot operators reported exploit attempts within hours of disclosure, including one that reached root on an Alpine honeypot. SANS ISC saw scanning peak on 6 November.
  • 9 November: CISA added CVE-2026-123158 to the KEV catalogue, with a 12 November due date for US federal agencies.
  • OpenSSH 10.6 (October 2026) also started deprecating scp -R and now warns about weak crypto by default (WarnWeakCrypto), so expect new warnings after a big jump in versions.

Troubleshooting

  • A scanner still flags my host after patching. Check the package revision against the table. Alpine’s fixed packages keep their older version numbers, so tools that only look for “10.6p2” report a false positive.
  • I patched but the check still looks vulnerable. You probably didn’t restart sshd. Run rc-service sshd restart, or docker restart for a container.
  • sshd -t fails after adding the drop-in. On Alpine older than 3.19 the sshd_config.d include may not exist. Delete the drop-in and put PasswordAuthentication no in /etc/ssh/sshd_config instead.
  • I locked myself out. Use your second session or the console to remove the setting. This is why you set up keys first and keep a session open.
  • Write-ups disagree on details. Some say the exploit works on the first try in one connection; one lab found it needed a second attempt in the same connection. Sources also differ on whether the length limit is 256 bytes or 256 characters. None of this changes the fix.

Keeping it safe

  • Prefer SSH keys over passwords everywhere, and keep PasswordAuthentication no even after you patch.
  • Don’t expose SSH to the internet if you can avoid it. Put it behind a VPN or a firewall rule that only allows your own addresses.
  • Lock accounts that should never log in with a password (passwd -l username sets !).
  • Rebuild container images on a schedule so base image fixes reach you without a fire drill.
  • Older SSH clients and servers can throw other errors after upgrades; see our fix for no matching host key type found.

Sources