Safeguard
Supply Chain Security•

Alpine OpenSSH Password Bypass (CVE-2026-123158): Find and Patch

sshd on Alpine without PAM accepts a long password for accounts whose shadow field is '*'. Check sshd, upgrade openssh and restart, or turn passwords off.

Safeguard Security Team
37 min read

On 5 November 2026, Alpine Linux and the OpenSSH project disclosed a password authentication bypass in sshd on musl libc systems built without PAM, now CVE-2026-123158. If you run sshd on Alpine with password logins enabled, upgrade openssh to the fixed build for your branch and restart sshd, or set PasswordAuthentication no today.

Most Alpine containers are not affected, because most containers never run sshd. The exposure sits in Alpine virtual machines, cloud instances, appliances, jump hosts, CI runners and the occasional container that bundles an SSH server. This post explains the bug in plain terms, lists the fixed version for every Alpine branch, and walks through how to find the hosts and images that matter, patch them, and check whether anyone got in first.

The short version

  • What it is: when sshd is built without PAM, it checks passwords by calling crypt() and comparing the result with the stored password field. musl's crypt() returns the string * on error, and it errors on any key longer than 256 bytes. An account whose shadow field is * therefore "matches" a long enough password. Alpine says an attacker who can reach the SSH port can log in "without knowing any password" in one connection.
  • Identifier: CVE-2026-123158, published by MITRE on 5 November 2026. Alpine's advisory was written before the ID existed and says none had been assigned at the time.
  • Who is affected on Alpine: systems running the openssh-server package (built without PAM), or openssh-server-pam with UsePAM no, where PasswordAuthentication is yes (the OpenSSH default), at least one account has * as its password field, and at least one local account has a $5$ or $6$ hash.
  • Fix: openssh 10.6_p2-r0 on edge, 10.3_p1-r2 on 3.24, 10.2_p1-r1 on 3.23, 10.0_p1-r11 on 3.22, with backports to every branch from 3.21 down to 3.16. Then restart sshd.
  • Exploitation: we found no report of exploitation in the wild in the sources listed below as of 6 November 2026, and the CVE is not in CISA's Known Exploited Vulnerabilities catalog (catalog version 2026.11.04). CISA's SSVC enrichment on the CVE records exploitation status as "poc", meaning public proof of concept material exists.

What happened

The bug sits where three ordinary design choices meet. None of them looks dangerous on its own.

First, Unix systems have used * in the password field for decades to mean "no password can match this". The researcher's write-up at sshhole.com traces it back to the daemon account in 3BSD in 1980. On Alpine, root has shipped as root:* in the base image since about Alpine 3.16, according to the Alpine advisory. Key-only users created without a password also get *.

Second, musl, the C library Alpine is built on, made crypt() return the string * on failure instead of a null pointer. The sshhole.com write-up dates that change to August 2012 and notes the intent was to fail closed for callers that do not check for null. A few weeks later, according to the same write-up, musl added SHA-512 crypt with a 256 byte key limit to bound the work an attacker can force. Past that limit, crypt() fails, and on musl a failure returns *.

Third, OpenSSH, when built without PAM, verifies a password itself. It hashes the attempt with crypt() using the salt from the stored hash and compares the output with the stored field. When the stored field is too short to contain a salt, such as *, sshd borrows the salt of another account. The researcher links that behaviour to the 2016 fix for CVE-2016-6210, a user enumeration bug through timing, which made sshd hash something realistic for every login attempt so that response times would not reveal which accounts exist.

Put the three together. A key-only account has * in its shadow field. Another account on the machine has a real $6$ hash, so sshd borrows a SHA-512 salt. The attacker sends a password longer than 256 bytes. musl's crypt() fails and returns *. sshd compares * with the stored *. They match, and the login succeeds.

The Alpine advisory states the practical result plainly: one connection, no retries, and "One user with a password is enough" to make every account without a password reachable. The attacker needs to know or guess an account name. On many systems that is easy: root, alpine on the official cloud images, or a service account name visible elsewhere.

Why upstream calls it a workaround

The OpenSSH release notes for Portable OpenSSH 10.6p2 describe the change as one to "avoid password authentication bypass" in sshd on some Linux systems built and run with PAM disabled. They add that the OpenSSH team considers the root cause to be outside sshd, but that the bug is exploitable through sshd and can be avoided there. The fix commit message, by Damien Miller (committed 4 November 2026, 21:18 UTC), says the same thing in fewer words.

That framing matters for scope. The CVE record describes sshd in OpenSSH before 10.6p2 as lacking a workaround, rather than describing a flaw in OpenSSH's own logic. On the oss-security list, the discussion on 5 and 6 November turned to what crypt() should return on error at all, with participants pointing out that POSIX says a null pointer, a Debian man page excerpt quoted in the thread says libxcrypt returns an invalid hash instead, chosen to fail closed, and the researcher says musl returns exactly *. You do not have to settle that debate to patch. It does tell you the fix lives in sshd and not in musl, so other programs that verify passwords through musl crypt() are a separate question for their own maintainers.

Timeline

Times are UTC where a source gives one. Dates without a time come from the source as written.

WhenWhatSource
1980* used in the password field of the daemon account in 3BSDsshhole.com
August 2012musl changes crypt() to return * instead of a null pointer on failuresshhole.com
29 August 2012musl adds SHA-512 crypt with a 256 byte key limitsshhole.com
2016OpenSSH fix for CVE-2016-6210 makes sshd hash with another account's salt; the researcher dates the bypass to roughly heresshhole.com
2019After CVE-2019-5021 (Alpine container images with an empty root password), root is locked with !sshhole.com
2022Alpine 3.16 (branched 23 May 2022) ships root:*, which stays locked for passwords but allows key logins without PAMAlpine advisory, Alpine releases page, sshhole.com
30 October 2026An OpenSSH commit fixes salt selection for bcrypt fake salts; the researcher says the bypass sits a few lines below itsshhole.com
1 November 2026Alpine 3.21 reaches end of supportAlpine advisory, Alpine releases page
Early November 2026Özgün Kültekin of Wakefield reports the bypass, four days after that commit by the write-up's accountsshhole.com, OpenSSH release notes
4 November 2026, 21:18OpenSSH fix commit 4353fdc43ef646c43a8dda7025cc1a898caf1482, "avoid password authn bypass"openssh-portable on GitHub
5 November 2026, 09:01Portable OpenSSH 10.6p2 announced on oss-securityoss-security, OpenSSH release notes
5 November 2026Alpine publishes its advisory and point releases 3.21.10, 3.22.8, 3.23.8 and 3.24.4Alpine advisory, Alpine release announcement
5 November 2026, 14:14The "sshole" thread starts on oss-security, linking the fix commit and the write-uposs-security
5 November 2026, 15:46CVE-2026-123158 published by MITRE as CNACVE.org record
5 November 2026, 16:17NVD receives the CVE (status "Received", not yet analysed by NVD)NVD
5 November 2026, 17:12CISA ADP adds SSVC: exploitation "poc", automatable "no", technical impact "total"NVD / CVE.org record
6 November 2026oss-security discussion continues on crypt() error semantics; no exploitation report found by usoss-security

Technical details

Identifiers and scores

FieldValueSource
CVECVE-2026-123158CVE.org, NVD
CNAMITRECVE.org
Affected (CVE record)OpenSSH before 10.6p2, platform LinuxCVE.org
CVSS 3.1 (MITRE)8.1 High, CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:HNVD, CVE.org
WeaknessCWE-394, Unexpected Status Code or Return ValueNVD
SSVC (CISA ADP)Exploitation: poc; Automatable: no; Technical impact: totalNVD
CISA KEVNot listed as of catalog version 2026.11.04CISA KEV feed
NVD statusReceived (no NVD score yet)NVD

Two small differences between sources are worth knowing. The CVE description says "any password between 256 and 1024 characters succeeds", while the Alpine advisory says 257 to 1024 bytes. The 256 byte limit in musl means a 256 byte key still hashes, so 257 is the first length that fails; we follow Alpine's figure. The upper bound of 1024 matches the MAX_PASSWORD_LEN limit defined in OpenSSH's auth-passwd.c. Second, the attack complexity in the CVSS vector is High, which reflects the preconditions on account setup. On a machine that meets them, the Alpine advisory says the login works every time.

The upstream fix

The fix is commit 4353fdc43ef646c43a8dda7025cc1a898caf1482 in openssh-portable, authored by Damien Miller and dated 5 November 2026 08:18 +1100 (4 November, 21:18 UTC). It touches three files: auth-passwd.c, openbsd-compat/port-uw.c and openbsd-compat/xcrypt.c. As the commit diff shows, and as the oss-security announcement of the write-up describes, the change makes sshd check the stored password field against a minimum hash length (MIN_PASSWORD_HASH_LEN, set to 4 in auth-passwd.c) rather than trusting whatever crypt() returns, so a one character error string can no longer pass as a match.

Portable OpenSSH 10.6p2 carries it. The release announcement gives these checksums for the tarball:

  • SHA1 (openssh-10.6p2.tar.gz): c91a0b7860c80f29db874044af4d1a6f906231d9
  • SHA256 (openssh-10.6p2.tar.gz), base64 encoded as OpenSSH publishes it: muRIcgkM8vBrPPn/FH5/FvMJZxNAdj7S+ZJIOYrinVs=

The OpenSSH team notes that the SHA256 value is base64, not hex, so compare it with openssl dgst -sha256 -binary openssh-10.6p2.tar.gz | base64 rather than with sha256sum. If you build OpenSSH yourself for an appliance or a custom image, verify the tarball's signature with the release key from the OpenSSH mirrors as usual.

Alpine's stable branches did not jump to 10.6p2. Each branch carries a patch for the same problem on its existing OpenSSH version, which is why the fixed versions below differ by branch.

Fixed Alpine packages

These are the fixed openssh versions from the Alpine advisory. We confirmed the edge and 3.20 to 3.24 versions against the openssh-server entries on pkgs.alpinelinux.org on 6 November 2026.

Alpine branchSupport status (Alpine releases page)Fixed opensshPoint release containing it
edgeRolling10.6_p2-r0Not applicable
3.24Supported until 1 June 202810.3_p1-r23.24.4
3.23Supported until 1 November 202710.2_p1-r13.23.8
3.22Supported until 1 May 202710.0_p1-r113.22.8
3.21End of support 1 November 20269.9_p2-r13.21.10
3.20Unsupported9.7_p1-r6None; package only
3.19Unsupported9.6_p1-r3None; package only
3.18Unsupported9.3_p2-r4None; package only
3.17Unsupported9.1_p1-r7None; package only
3.16Unsupported9.0_p1-r6None; package only

Alpine says every release it checked, 3.21 through 3.24 and edge, plus the older 3.16 to 3.20, is affected. It published fixed packages back to 3.16 even though those branches no longer receive regular updates. That is generous, and it is also a signal: if you still have hosts on 3.16 to 3.21, this is a good week to plan their move to a supported branch.

The openssh source package builds several binary packages. The vulnerable code path is in the server, so the package that matters on a host is openssh-server (or openssh-server-pam), but apk upgrades the subpackages together, and you should check the version of whichever server package is installed.

Preconditions, in one place

All of these must be true for a system to be exploitable, per the Alpine advisory:

ConditionHow to checkNotes
sshd is installed and runningrc-service sshd status, pgrep -a sshdContainers without sshd are not affected
Built without PAM, or PAM disabledapk info -e openssh-server, sshd -T shows usepam noopenssh-server-pam with UsePAM yes is not affected
PasswordAuthentication yessshd -T shows passwordauthentication yesThis is the OpenSSH default
An account with * as its password fieldawk -F: '$2=="*"' /etc/shadowroot since about 3.16, key-only users, tiny-cloud alpine user
At least one account with a $5$ or $6$ hashawk -F: '$2 ~ /^\$[56]\$/' /etc/shadowSupplies the salt that sshd borrows

Directory users need their own mention. The advisory says users that come from a directory service through musl-nscd (with nslcd, winbind or sssd behind it) have no shadow entry, so they behave like * accounts here. If your Alpine hosts resolve users from LDAP or Active Directory and you are not on openssh-server-pam with UsePAM yes, assume those accounts are reachable.

Root is a partial exception. OpenSSH's default PermitRootLogin prohibit-password blocks password logins for root, so root itself is reachable only when PermitRootLogin yes is set. The advisory warns that this does not help when another account that can log in is able to become root, for example through doas.

The tiny-cloud images

This is the case most likely to surprise people. The Alpine advisory says the official tiny-cloud images (the qcow2, VHD and AMI artifacts) from 3.18.11 through 3.24.3 ship an alpine user with a * password field and passwordless doas. They are safe on first boot because no account has a real hash yet. They become exploitable as soon as any $6$ hash appears on the machine, for example when an administrator sets a console password, or when user data adds a user with a hashed password. From there, Alpine says, an attacker gets a shell as alpine and can use doas to become root.

Images built from 3.21.10, 3.22.8, 3.23.8, 3.24.4 and later include the fixed package. Instances already running from older images do not fix themselves when a newer image is published. Each running instance needs the package upgrade and an sshd restart, or password authentication turned off.

Cloud images configured through cloud-init are not affected, according to the advisory, because cloud-init writes PasswordAuthentication no.

What the researcher claims beyond Alpine

The sshhole.com write-up by Özgün Kültekin describes the affected set as OpenSSH on musl based Linux without PAM, and names OpenWrt, Buildroot, Yocto and "a lot of the docker images" alongside Alpine. That wider scope is the researcher's claim. We have not seen vendor advisories from those projects confirming it at the time of writing, and many builds from those systems use a different SSH server or enable PAM. Treat it as a prompt to check your own embedded and appliance builds, not as a confirmed list.

The same write-up says glibc systems, PAM based setups, Dropbear and OpenBSD are not affected. It also describes the method: building OpenSSH against glibc and musl, with and without PAM and shadow, and running a large set of unusual login attempts against each, with every build agreeing except musl without PAM. The OpenSSH 10.6p2 announcement adds context of its own: the team says it has received many AI assisted security reports, has seen cases where a bug found with AI tools was later found independently by someone else, and will for now ship more frequent releases rather than batching fixes.

Who is affected, and who is not

SituationAffected?Why
Alpine container image that does not run sshdNoAlpine lists container users that do not run sshd as not affected
Alpine container image that bundles and starts sshd, with password logins onPossiblyCheck the preconditions inside the running container
Alpine VM or bare metal host with openssh-server, defaults unchanged, one user with a password, root as root:*Yes, for any * account that can log inRoot itself only with PermitRootLogin yes, but other * accounts are reachable
Official Alpine tiny-cloud image, 3.18.11 to 3.24.3, after any $6$ hash is addedYes, with a path to root through doasPer the Alpine advisory
Alpine image configured with cloud-initNocloud-init writes PasswordAuthentication no
PasswordAuthentication noNoThe password path is never used
openssh-server-pam with UsePAM yesNoPAM handles the password check
openssh-server-pam with UsePAM noYes, if the other conditions holdsshd falls back to its own crypt() check
Accounts locked with !NoLocked accounts cannot log in with a password or a key
No account has a $-style hashNoThere is no salt for sshd to borrow
Debian, Ubuntu, RHEL and other glibc distributionsNo, per the researcherglibc's crypt() does not return a bare *
OpenWrt, Buildroot, Yocto builds with OpenSSH on musl and no PAMPossibly; researcher's claimCheck your build configuration

The honest summary for most teams: if you use Alpine only as a container base image and your containers run one application process each, you probably have nothing to patch for this bug. Rebuild on the next point release as normal hygiene. Spend your time on the hosts and the few images where sshd actually runs.

What to do now

1. Find every place sshd runs on Alpine or musl

Start with hosts, because that is where the risk concentrates. On each Alpine machine:

# Is an SSH server package installed, and which one?
apk info -v 2>/dev/null | grep -E '^openssh-server'

# Is sshd running?
rc-service sshd status 2>/dev/null; pgrep -a sshd

# Which Alpine release?
cat /etc/alpine-release

For a fleet, run the same checks over SSH using your inventory, or through your configuration management tool. Collect the hostname, Alpine release, installed server package and version, and whether sshd is running.

For container images, look at what an image would run, not just what it contains:

# Does the image contain an SSH server package?
docker run --rm --entrypoint /bin/sh IMAGE -c \
  'cat /etc/alpine-release; apk info -v 2>/dev/null | grep -E "^openssh-server"'

# What does the image start, and does it expose port 22?
docker inspect --format '{{.Config.Entrypoint}} {{.Config.Cmd}} {{.Config.ExposedPorts}}' IMAGE

In Kubernetes, look for workloads that declare port 22 or run an SSH server:

kubectl get pods -A -o json | jq -r '
  .items[] | . as $p | .spec.containers[] |
  select((.ports // [])[]?.containerPort == 22) |
  "\($p.metadata.namespace)/\($p.metadata.name) \(.image)"'

An SBOM for each image you build makes the first question fast across hundreds of images. Search your SBOMs for the openssh-server and openssh-server-pam packages with Alpine package URLs (for example pkg:apk/alpine/openssh-server) and list the versions. That gives you a candidate list. The second question, whether sshd actually starts, needs the entrypoint, the process list in running containers, or both.

Do not forget the places that are easy to miss: bastion and jump hosts built on Alpine, self-hosted CI runners, small VMs that someone made "temporarily" in 2023, network and storage appliances whose vendor builds on Alpine, and development containers that teams start with an SSH server for remote editing.

2. Compare the installed version with the fixed version for its branch

apk can compare versions for you, which avoids mistakes with the _p and -r suffixes:

# Prints "<" if the installed version is older than the fix
apk version -t "$(apk info -v 2>/dev/null | sed -n 's/^openssh-server-\([0-9].*\)$/\1/p' | head -1)" 10.3_p1-r2

Replace 10.3_p1-r2 with the fixed version for the host's branch from the table above. A host on 3.23 compared against the 3.24 fix will look outdated when it is not, so always compare within the same branch. If you are not sure which branch a host follows, check /etc/apk/repositories as well as /etc/alpine-release.

3. Check the configuration that decides exposure

The scanner can tell you a vulnerable package is present. Only the running configuration can tell you whether that package is exposed. Ask sshd for its effective settings rather than reading the file, because Include files and Match blocks change the result:

sshd -T 2>/dev/null | grep -Ei '^(usepam|passwordauthentication|permitrootlogin) '

Then look at the accounts:

# Accounts whose password field is exactly "*"
awk -F: '$2=="*" {print $1}' /etc/shadow

# Accounts with a SHA-256 or SHA-512 crypt hash
awk -F: '$2 ~ /^\$[56]\$/ {print $1}' /etc/shadow

If the first command prints accounts that can log in, the second prints at least one account, and sshd reports passwordauthentication yes with usepam no, the host is exposed until you fix it.

Note that sshd -T evaluates the default connection. If you use Match blocks to enable passwords for some users or addresses, test them with sshd -T -C user=NAME,host=HOST,addr=ADDR.

4. Upgrade and restart

On a host that can take the update:

apk upgrade -U -a
rc-service sshd restart

Those are the commands from the Alpine advisory. The restart is not optional. Alpine says upgrading the package does not restart a running sshd, and both the advisory and the release announcement tell you to restart after updating. Confirm afterwards:

apk info -v | grep -E '^openssh-server'
rc-service sshd status

Keep your current session open while you restart, and test a new login from a second terminal before closing it.

5. If you cannot upgrade today, turn off password authentication

The Alpine advisory gives a mitigation that works on its own. Make sure key based login works first, and keep your session open until you have tested a new login. As root:

mkdir -p /etc/ssh/sshd_config.d
echo 'PasswordAuthentication no' > /etc/ssh/sshd_config.d/00-no-passwords.conf
sed -i.bak -e '1i PasswordAuthentication no' \
  -e 's/^\(\s*PasswordAuthentication[^y#]*\)yes/\1no/i' \
  /etc/ssh/sshd_config
sshd -t && rc-service sshd restart
sshd -T | grep -i passwordauthentication

The last command should print passwordauthentication no. Alpine notes that its default sshd_config reads the sshd_config.d directory from 3.19 onward and that older releases ignore it, which is why the sed line also rewrites the main file, including lines inside Match blocks. To undo, delete the drop-in file and restore /etc/ssh/sshd_config.bak.

For many servers, leaving passwords off permanently is the better end state. If people need passwords for a reason, consider openssh-server-pam with UsePAM yes, which Alpine lists as not affected, and test it on one host before rolling it out.

6. Rebuild images and replace instances

For images that do run sshd, rebuild from a base that includes the fixed package and redeploy. In a Dockerfile that installs the server, an explicit upgrade on top of a pinned base makes the intent visible in review:

FROM alpine:3.24.4
RUN apk add --no-cache openssh-server && apk upgrade --no-cache openssh-server

Pin to the point release (3.24.4, 3.23.8, 3.22.8, 3.21.10) or a digest you have verified, rather than a floating tag, so you know which build you are running. Then check the running container, not just the image you pushed: a pod that started last week still runs last week's image until it restarts.

For VMs from the tiny-cloud images, build new images from 3.21.10, 3.22.8, 3.23.8, 3.24.4 or later, and patch running instances in place in the meantime. Replacing an image in your launch template does nothing for the instances already running.

7. Look for signs of use before you patched

Alpine's guidance is to look in /var/log/messages for sshd lines reading Accepted password for an account that has no password, such as alpine, root or any key-only user:

# Default syslog on Alpine
grep -h 'sshd' /var/log/messages* 2>/dev/null | grep 'Accepted password for'

# Then compare the user names against the "*" accounts
awk -F: '$2=="*" {print $1}' /etc/shadow

Any Accepted password for line that names a * account is a strong signal, because that account has no password that could legitimately be accepted. Alpine also recommends reviewing doas use, recently created users, new files and changes to authorized_keys on exposed machines, and says that if you cannot rule out a login, you should treat the machine as compromised. If you ship logs to a central system, search there too, because an attacker with root can edit local logs.

# New or changed authorized_keys in the last 30 days
find / -xdev -name authorized_keys -mtime -30 2>/dev/null

# doas usage, if logged
grep -h 'doas' /var/log/messages* 2>/dev/null | tail -50

We found no report of exploitation in the wild as of 6 November 2026. Public write-ups and reproduction labs exist, and CISA's SSVC assessment records proof of concept material, so do not treat the lack of reports as a reason to wait.

What changed since first reports

The story moved quickly on 5 November, and early reports differ from the current record in a few ways.

  • CVE: the Alpine advisory says no CVE had been assigned when it was written. MITRE published CVE-2026-123158 later the same day, and NVD received it shortly after. Use the CVE ID in tickets and scanner policy so results line up.
  • Score: the only score so far is MITRE's CVSS 3.1 base score of 8.1 High. NVD had not analysed the record when we checked. Expect that some tools will show "no score" or a different score until NVD completes its analysis.
  • Framing: the OpenSSH release notes call it a workaround for a root cause outside sshd that only affects some Linux systems built and run without PAM. glibc distributions are not affected according to the researcher.

Open questions

  • Other musl distributions and embedded builds. The researcher names OpenWrt, Buildroot and Yocto. At the time of writing we had not seen their own advisories. Embedded builds vary widely in which SSH server they ship and whether PAM is enabled, so each needs its own check.
  • Other programs that verify passwords through musl crypt(). The OpenSSH fix only protects sshd. Whether any other software on musl compares a crypt() result with a stored * in the same way is an open question for those maintainers. The oss-security thread discusses the general problem without naming other affected programs.
  • NVD analysis. NVD may add its own score and configuration data. That could change how automated tools rank this CVE.
  • Vendor appliances. Appliance vendors that build on Alpine and ship sshd with password logins enabled will need to publish their own fixes. Check with your vendors rather than waiting for a scanner to tell you.

What would have helped

Practices any team can use

Keep an inventory that answers "where does sshd run?" A list of installed packages is not enough here. Most Alpine images contain no SSH server; some contain the package but never start it; a few start it. The inventory that helps is one that ties each host and image to its packages, its Alpine branch and whether it listens on port 22. An SBOM per image answers the first two quickly. Runtime data, or at least the declared entrypoint and ports, answers the third.

Default to PasswordAuthentication no on servers. This bug is only reachable through the password path. Teams whose server baseline already turned passwords off had nothing to do but patch on their normal schedule. If you need passwords, put them behind PAM with UsePAM yes, which Alpine lists as not affected.

Audit account states, not just account names. * and ! look similar in /etc/shadow and mean different things to sshd without PAM. A periodic check that lists accounts by password field type (*, !, hash prefix) would have flagged the risky mix this bug needs: a * account that can log in, next to a hashed one.

Treat restart as part of patching. An upgraded package and a running daemon are two different facts. Patch automation that upgrades sshd should restart it, and verification should check the running state, not just apk info.

Rebuild cloud images and replace instances. Official images from before the point releases carry the vulnerable package. Updating the image in a launch template protects new instances only.

Restrict who can reach port 22. Security groups, firewalls and bastion patterns that keep SSH off the internet turned this from a remote login bug into an internal one for many teams. That is not a fix, but it buys time.

Where Safeguard fits

Safeguard did not discover this bug. It was reported to OpenSSH by Özgün Kültekin of Wakefield. Here is what Safeguard does that is relevant, and where it stops.

Inventory and matching. The Safeguard CLI scans repositories, container images and SBOM files (safeguard scan --dir ., safeguard scan --image <name>, safeguard scan --sbom <file>) and writes results as JSON under ./output. Those scans produce an SBOM that includes the Alpine packages in an image, and vulnerability matching compares them against vulnerability databases. The platform shows which projects contain a given component and version, so you can ask which images carry openssh-server and at which version, and compare each against the fixed version for its branch.

Policies and gates. Safeguard policies and gates are evaluated in the platform and can run in CI with safeguard exec. A policy that fails the build or blocks promotion when an image contains openssh-server below the fixed version for its branch stops new vulnerable images from shipping while you clean up the old ones.

Prioritization. Reachability analysis ranks vulnerable code paths your application actually calls. For an OS package like this, the more useful signal is whether sshd runs at all, which an image scan cannot see on its own. Pair the scan results with the configuration checks above.

Remediation. For images you build, autonomous remediation can open a policy gated pull request that bumps a pinned base image tag or package version in a Dockerfile, and your own CI runs your tests before anyone merges. Auto-merge is off by default. The Safeguard CLI's assistant can also make the change with you in a terminal, asking before any command that changes something.

Where Safeguard does not help directly. A scan does not read the effective sshd configuration on a running VM, does not inspect /etc/shadow on your hosts, and does not restart daemons. Hosts, appliances and running instances still need the configuration checks, the restart and the log review described above. Vendor appliances need the vendor's fix.

Zero-Day Discovery and Gold

Safeguard's Zero-Day Discovery looks for previously unknown flaws in open source packages before a CVE exists, in an agentic mode and a deterministic scanner mode, and issues what it finds as SGZ advisories. It had no part in this disclosure, and this bug sits at the meeting point of a C library, an OS package and a server configuration rather than inside a single application dependency.

Gold Open Source at gold.safeguard.sh is a free, no login lookup for CVE intelligence: CVSS, EPSS, KEV status, affected and fixed versions and a recommended safe version. Search there for CVE-2026-123158 and check whether a record exists and what it says before you rely on it. For Alpine package versions, the Alpine advisory and pkgs.alpinelinux.org remain the authority.

The habit that helps most is pulling patched, signed base images from a source you trust and rebuilding fast when a fix lands. For this bug, upstream has shipped: OpenSSH 10.6p2 and Alpine's fixed packages are out. The gaps that remain are the time it takes those packages to reach every image and instance you run, and hosts on Alpine branches past end of support (3.16 to 3.21), which got backports this time but may not next time. The next section explains how Safeguard helps with both in general terms. We make no claim that Gold has or had a patched build of this specific package.

Common mistakes

Upgrading without restarting. The most likely way to stay exposed after "patching". Alpine says it plainly: the package upgrade does not restart sshd.

Treating every Alpine container as affected. It wastes a week of rebuilds on images that never run sshd, and it hides the few that do. Filter on whether sshd starts.

Treating every Alpine container as safe. Some do run sshd: development containers, legacy "VM in a container" images, some CI and test images. Check.

Comparing versions across branches. 10.0_p1-r11 is fixed on 3.22 even though 10.3_p1-r2 is the 3.24 fix. Compare within the branch the host uses.

Reading sshd_config instead of asking sshd. Include files, drop-ins and Match blocks change the effective value. Use sshd -T.

Assuming PermitRootLogin prohibit-password is enough. It protects root's password login, but not other * accounts, and not a path to root through doas from one of them.

Locking yourself out. Turning off passwords on a host where nobody has a working key. Test key login from a second session first, as Alpine advises.

Waiting for the scanner score. NVD had not scored the CVE when we checked. Some tools rank unscored CVEs low. Override that for this one on any host where sshd runs.

FAQ

Is CVE-2026-123158 an OpenSSH bug or a musl bug?

Both projects play a part. musl's crypt() returns * on error, and sshd without PAM compared that output with a stored *. The OpenSSH team says it considers the root cause outside sshd, but it shipped a workaround in 10.6p2 because the bug is exploitable through sshd. For patching purposes, the fix is in the openssh package.

Are my Alpine Docker containers affected?

Only if they run sshd with password authentication enabled and meet the account conditions. Alpine lists container users that do not run sshd as not affected, which covers most application containers. Check images that install openssh-server and start it.

Is it being exploited?

We found no report of exploitation in the wild as of 6 November 2026, and the CVE is not in CISA's KEV catalog (version 2026.11.04). CISA's SSVC enrichment records that proof of concept material exists. Assume capable attackers can reproduce it.

What versions fix it?

On Alpine: 10.6_p2-r0 (edge), 10.3_p1-r2 (3.24), 10.2_p1-r1 (3.23), 10.0_p1-r11 (3.22), 9.9_p2-r1 (3.21), and backports for 3.16 to 3.20 listed in the table above. Upstream: Portable OpenSSH 10.6p2. Restart sshd after upgrading.

I use openssh-server-pam. Am I safe?

Yes, if UsePAM yes is in effect. Alpine says openssh-server-pam with UsePAM no is affected. Confirm with sshd -T | grep -i usepam.

My server only allows key logins. Am I safe?

If PasswordAuthentication no is in effect, yes. If you only rely on users having no password, no: that * field is exactly what this bug turns into an open door. Check sshd -T.

Are Debian, Ubuntu or RHEL servers affected?

Not according to the researcher, who says glibc systems and PAM based setups are not affected. Those distributions use glibc and normally build OpenSSH with PAM.

What about OpenWrt, Buildroot and Yocto?

The researcher names them as part of the wider musl scope. That is the researcher's claim, and at the time of writing we had not seen confirming advisories from those projects. Check whether your build ships OpenSSH, uses musl, and has PAM disabled with password authentication on.

How do I tell if someone already used it?

Search /var/log/messages (and your central logs) for Accepted password for lines naming accounts whose shadow field is *. Review doas use, new users, new files and authorized_keys changes. Alpine advises treating the machine as compromised if you cannot rule out a login.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Griffin, Safeguard's security model, opens a policy gated pull request that moves the affected dependency to the safe version, and your own CI runs your tests on it before anyone merges. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Auto-merge is a separate switch and stays off by default, so your team decides what merges on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.

3. Gold Registry: start from components that are already fixed

Safeguard Gold rebuilds patched versions of open-source packages and images from source, signs each build, attaches an SBOM, SLSA provenance and VEX, and serves them from registry.safeguard.sh to your organization. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened build of a specific package. Ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingSafeguard policies and gates in CI
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session. You install the CLI, run safeguard to open the interactive terminal and ask it to fix a lodash CVE in a repository. It reads the vulnerability and the advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The demo shows an npm change, not an Alpine one. For an image that runs sshd, you would make the same kind of request against the Dockerfile, asking it to move the base image to alpine:3.24.4 or the fixed point release for your branch, then review the diff and let your CI build and test it.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with its device code, then scans from the terminal. For a platform team with many images, that is how you would run safeguard scan --image across the images in your own registry from your own infrastructure and collect which ones carry openssh-server.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. Once connected, you can ask an assistant which of your projects contain a given package and version while you plan the rollout. Whether a given CVE is in your workspace's data depends on your account, so confirm fixed versions against the Alpine advisory.

Click through it at your own pace, or open it full screen.

To try it on your own images, download Safeguard or start with the CLI documentation. For background on finding affected products from SBOMs, see SBOM incident response: finding affected products fast and our review of container image supply chain incidents in 2026.

Quick check

Your Alpine 3.23 host shows openssh-server 10.2_p1-r1 after the upgrade. Are you done?

Not until sshd has restarted. 10.2_p1-r1 is the fixed version for 3.23, but the running daemon keeps the old code until you run rc-service sshd restart.

An application container is built FROM alpine:3.22.7 and runs only a Go binary. Does it need an emergency rebuild for this bug?

No. It does not run sshd, which Alpine lists as not affected. Rebuild on 3.22.8 as part of normal hygiene.

A host has PermitRootLogin prohibit-password, root:* and a "deploy" user with a key and no password. Is it exposed?

Yes, if password authentication is on, sshd runs without PAM and any account has a $5$ or $6$ hash. Root is protected by prohibit-password, but the deploy account is not.

Sources

Last reviewed: 6 November 2026. This is a developing story; check the linked advisories for the latest status.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

We email you a link to confirm, and only then add you to the list. Unsubscribe in one click. Privacy

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.