Skip to content

SSHole logged into accounts that were not supposed to have a password (CVE-2026-123158)

CVE-2026-123158 SSHole: OpenSSH musl Bypass, Alpine Fixes, Log Hunt

SSHole logged into accounts that were not supposed to have a password (CVE-2026-123158)

your key-only alpine user was never supposed to accept a password. then someone typed a very long one, musl’s crypt() handed back a star, and sshd treated that star as a match. the researcher who found it called the bug sshole. OpenSSH shipped 10.6p2 on November 5. a honeypot operator says the scanners showed up the same day. CISA has not put it on KEV as of our November 8 check of the official catalog.

Lab-only / defensive use. everything below is version checking, config review, and log hunting. the downloadable scripts read files you export yourself, make no network connections, and contain no exploit or login code. we are not linking public proof-of-concept repos. Help Net Security quoted Previdian warning that unverified GitHub PoCs for this bug may contain malware. do not fetch them.
What happened. MITRE published CVE-2026-123158 on November 5, 2026. the description says sshd in OpenSSH before 10.6p2 on Linux, when musl libc is used without PAM, “lacks a workaround for a password authentication bypass (related to misinterpretation of whether a string is intended to be a password hash).” for some account configurations, “any password between 256 and 1024 characters succeeds.” Alpine Linux, a common musl-without-PAM platform, published a same-day advisory and patched packages back to the 3.16 branch. OpenSSH 10.6p2, also dated November 5, calls it “a critical security workaround” and says the project considers the root cause to be outside sshd, even though it is exploitable through sshd. Previdian founder Ryan Dewhurst told Help Net Security the firm’s first observed attempt arrived less than nine hours after CVE publication, and that a honeypot running real Alpine Linux and OpenSSH saw successful root access.

the exact condition, no inflation

this is not “every OpenSSH box on the internet is wide open.” the MITRE record limits the bug to Linux sshd built and run with musl and without PAM. Alpine’s advisory is more specific about what has to be true at the same time on an Alpine box:

  • the package is the default Alpine openssh-server, which is built without PAM, or you run openssh-server-pam with UsePAM no. Alpine says openssh-server-pam with UsePAM yes is not affected.
  • PasswordAuthentication is yes. that is the OpenSSH default unless you changed it. Alpine says setting it to no closes the hole.
  • the machine has an account whose password field is *. Alpine lists root (shipped as root:* in the base image since about Alpine 3.16), any key-only user created with adduser without a password or with usermod -p '*', users coming from a directory service through musl-nscd (nslcd, winbind, sssd) because they have no shadow entry, and the alpine user in the official tiny-cloud images.
  • at least one local account has a $5$ or $6$ password hash. Alpine’s wording: “one user with a password is enough: it makes every account without one reachable.”

Alpine is also explicit about root itself. OpenSSH’s default PermitRootLogin prohibit-password protects the root account, “so root is only reachable if PermitRootLogin yes is set.” that does not help “if another account that can log in is able to become root, for example through doas.” Help Net Security quoted researcher Özgün Kültekin of Wakefield on the official AWS and Azure Alpine images: “on alpine’s official aws and azure images that’s the default alpine user, and it has passwordless doas. so it’s root.”

who is not affected, still from Alpine: containers that do not run sshd, systems with PasswordAuthentication no, openssh-server-pam with UsePAM yes, locked accounts whose password field is ! (Alpine: they cannot log in with a password or a key), systems where no account has a $-style password hash, and cloud images configured through cloud-init, which writes PasswordAuthentication no.

Help Net Security, summarizing the researcher, also said systems built on glibc (Debian, Ubuntu and Fedora among them), setups that go through PAM, Dropbear, and OpenBSD are safe. that matches the CVE’s Linux-plus-musl-without-PAM scope. Kültekin, again via Help Net Security and SecurityWeek, listed OpenWrt, Buildroot and Yocto among other musl-based systems worth checking, “along with a lot of the docker images you’ve pulled.” the CVE record itself names Alpine as the example, not those other projects, so treat OpenWrt, Buildroot and Yocto as researcher-flagged lookalikes, not as named affected products in the CVE JSON.

scores, and who gave them

  • MITRE (CNA): CVSS 3.1 8.1 HIGH, CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H. the High attack complexity matches the stacked conditions above. NVD’s listing, when we checked it on November 8, had not published its own base score (“NVD assessment not yet provided”).
  • CISA ADP enrichment in the CVE record: SSVC options dated 2026-11-05 list Exploitation as poc (not “active”), Automatable as no, and Technical Impact as total.
  • CWE-394, unexpected status code or return value, assigned by MITRE.
  • CISA KEV: not listed as of our November 8 download of the official CISA KEV JSON (catalogVersion 2026.11.06, dateReleased 2026-11-06T19:44:45Z). that feed’s newest entry was CVE-2026-19868 (SonicWall SonicOS SSLVPN), added November 6 with a November 20 due date. Help Net Security reported on November 6 that Previdian had put the OpenSSH bug on its own exploited list “while CISA has not included it in its KEV catalog.” we are not going to pretend a third-party aggregator is CISA.

credit: Özgün Kültekin of Wakefield, named in the OpenSSH 10.6p2 release notes and in Alpine’s advisory. Alpine also thanks Damien Miller and Darren Tucker of OpenSSH, Timo Teräs, and Natanael Copa, who built and uploaded the updated packages.

how a star becomes a yes (the vendor explanation, not a recipe)

we are going to quote the people who shipped the fix, then stop. this is not a tutorial.

Alpine: when sshd is built without PAM, it checks a password by hashing the attempt with crypt() and comparing the result to the stored password field. for an account whose stored field is too short to contain a salt, sshd borrows the salt of another account. “musl’s crypt() returns the string * as an error indicator when the key is over 256 bytes long. * is also exactly what the stored field contains for every account with no password, so the ‘hash’ matches and the login succeeds.”

Help Net Security’s write-up of Kültekin’s explanation adds the historical why: in 2016, to fix a timing issue that let attackers work out which usernames exist (CVE-2016-6210), OpenSSH changed sshd so that it borrows another account’s salt and hashes the password anyway when an account has no usable hash. since 2012, musl’s crypt() has refused SHA-256 and SHA-512 passwords longer than 256 bytes and returned * on failure.

OpenSSH’s own 10.6p2 notes are careful about blame: “We consider the root cause of this bug to be outside sshd, but it is exploitable via sshd and can be avoided there.” the project also said it learned of the problem the day before the release, and that it is shipping faster because “we have recently observed multiple cases of rapid bug rediscovery by AI agents, sometimes within hours, and so now consider long embargo periods to be a dangerous practice that primarily benefits attackers.” SecurityWeek quoted Damien Miller on that point. Help Net Security quoted him separately on Mastodon telling anyone running musl-based Linux without PAM to “stop reading and set PasswordAuthentication=no or disable SSH for these systems IMMEDIATELY.”

one number disagreement, stated plainly: the MITRE CVE text says “any password between 256 and 1024 characters succeeds.” Alpine’s advisory says the attacker “sends a very long password (257 to 1024 bytes).” SecurityWeek wrote “between 257 and 1,024 characters.” Alpine’s mechanism sentence (“over 256 bytes”) lines up with 257 and up. we are not going to pick a winner for the exact 256-byte case. if you are writing a detector, you do not need that byte. you need the version, the libc, the PAM flag, and the logs.

affected Alpine releases and the actual fixed packages

Alpine checked every release from 3.21 through 3.24 and edge, plus the older releases that no longer receive regular updates (3.16 to 3.20). 3.21 reached end of support on November 1, 2026, but Alpine still published fixed packages back to 3.16. the fixed package versions from the advisory are:

  • edge: 10.6_p2-r0
  • 3.24: 10.3_p1-r2
  • 3.23: 10.2_p1-r1
  • 3.22: 10.0_p1-r11
  • 3.21: 9.9_p2-r1
  • 3.20: 9.7_p1-r6
  • 3.19: 9.6_p1-r3
  • 3.18: 9.3_p2-r4
  • 3.17: 9.1_p1-r7
  • 3.16: 9.0_p1-r6

that table is why a sloppy “anything below 10.6p2 is vulnerable” scanner will lie to you on Alpine. a 3.24 box running 10.3_p1-r2 is patched, even though 10.3 is older than 10.6. OpenSSH 10.6p2 is the upstream floor. Alpine’s stable branches carry a backport. Alpine 3.21.10, 3.22.8, 3.23.8 and 3.24.4 contain the fixed package, per the advisory’s release announcement pointer.

then restart sshd. Alpine, twice, because people will forget: “Upgrading the package alone does not replace the running daemon.” the command they document is rc-service sshd restart after apk upgrade -U -a.

tiny-cloud images, the boring detail that becomes root

Alpine’s official tiny-cloud images (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.” they “become exploitable as soon as any $6$ hash exists on the machine, for example when an admin sets a console password, or user-data adds a user with hashed_passwd.” an attacker then “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. older point releases do not, so every running instance still needs the package update or PasswordAuthentication no.

Help Net Security attributed the same 3.18.11 through 3.24.3 range to SOCRadar. Alpine’s own advisory is the primary source we are using for that range.

Kali terminal running the offline sshole-123158-host-check.py against a sample lab inventory CSV, flagging two unpatched Alpine hosts as VULN, marking a 3.24 backported package, a PasswordAuthentication no host, a UsePAM yes host and a glibc Debian bastion as OK, and leaving an unknown row as REVIEW.
Step 0: compare each sshd against the upstream 10.6p2 floor and the Alpine backport table, then check the runtime conditions Alpine documented. sample lab inventory only.

exploitation reports, without turning them into a scoreboard

Previdian, via Help Net Security (November 6): first observed attempt less than nine hours after CVE publication. confirmed successful root access on a honeypot running real Alpine Linux and OpenSSH. the observed source address was 89.116.89[.]18. Dewhurst said it used oversized passwords and ran reconnaissance commands including id, uname and hostname through non-interactive SSH sessions. eight attempts, all from that single Japan-based address, all caught by one sensor. Previdian put the bug on its own known-exploited list.

that is one vendor’s honeypot telemetry, reported through a trade publication. it is not a CISA KEV listing, and CISA’s own ADP enrichment on the CVE still said “poc” on November 5. both things can be true: a researcher-built PoC exists, and at least one operator says a real scanner used the bug against a real Alpine sshd. we are not going to upgrade Previdian’s eight attempts into “mass exploitation” or invent victim counts that nobody published.

Kültekin told Help Net Security he built sshd in every combination he could think of and threw some 17,600 unusual login attempts at the builds. “only the musl build without PAM let in logins it should have refused.” he also said, in the same interview, that he had “agent swarms. a lot of them.” OpenSSH’s release notes are independently worried about AI-speed rediscovery. that is context, not proof that every attacker on the internet now has a working copy.

what to do today

  1. inventory sshd, not just “Linux.” you want the OpenSSH version string, whether the box is musl, whether PAM is in use (sshd -T and the package name both matter on Alpine), PasswordAuthentication, PermitRootLogin, whether any account’s password field is *, and whether any local account has a $5$ or $6$ hash. official Alpine AWS/Azure/tiny-cloud images deserve their own column.
  2. patch, then restart the daemon. upstream: OpenSSH 10.6p2 or later. Alpine: the package version in the table above for your branch, then rc-service sshd restart. if you cannot patch yet, Alpine documents setting PasswordAuthentication no via a drop-in under /etc/ssh/sshd_config.d/ (read from 3.19 onward) plus a sed of /etc/ssh/sshd_config, then sshd -t and a restart. confirm key login works first, and keep your current session open until a new login succeeds. sshd -T | grep -i passwordauthentication should print passwordauthentication no.
  3. hunt the log line Alpine told you to hunt. look in /var/log/messages (or your shipped journal) for sshd lines reading Accepted password for an account that has no password: alpine, root, or any key-only user. review doas use, recently created users, new files, and authorized_keys on exposed machines. Alpine: “If you cannot rule out a login, treat the machine as compromised.”
  4. do not collect random GitHub PoCs. Help Net Security quoted Previdian saying public proof-of-concept exploits have been posted and that they are unverified and could contain malware. you do not need one to patch or to read your own logs.
Kali terminal running the offline sshole-123158-log-review.py against a sample lab auth.log and a list of passwordless accounts, flagging two Accepted password lines for the alpine user from documentation address 203.0.113.88 while counting one legitimate publickey login and one password login for an account that actually has a hash.
Step 1: flag Accepted password lines for accounts whose password field is *. sample lab log only, a heuristic not a verdict. the source address in the screenshot is a documentation IP, not live telemetry.

download the Kali defensive checks

sshole-123158-defensive-check.zip contains two offline Python scripts. sshole-123158-host-check.py reads an inventory CSV you export (name, distro, OpenSSH version, Alpine package and branch, libc, UsePAM, PasswordAuthentication, whether a * account exists, whether a $5$ or $6$ hash exists, PermitRootLogin) and compares it against OpenSSH 10.6p2 and Alpine’s backport table. sshole-123158-log-review.py reads an auth log export plus the list of accounts you already know are passwordless, and prints Accepted password for hits. neither connects to a host, neither attempts a login, and neither proves compromise on its own.

the sloth take

a password field of * was supposed to mean “this account does not take a password.” musl used the same character as an error. sshd, trying very hard not to leak whether a username exists, hashed the attempt anyway and compared the error to the placeholder. the equals sign did the rest. that is not a failure of MFA, SAML, or your shiny zero-trust slide. it is a C library and a daemon disagreeing about what a star means, on the Linux distribution that markets itself as small, simple, and secure, plus whoever else copied the musl-without-PAM combo into a router image or a container you forgot was listening on 22.

patch the package. restart the process that is still running the old binary. then go find out how many of your “key-only” users ever accepted a password. the sloth would like to believe the answer is zero. the sloth has read honeypot notes before.

related reading on the site: last week’s reminder that “the scanners showed up before your change window” was SonicWall’s SSLVPN SAML bypass landing on CISA KEV. different product, same weekend energy.

if you have Alpine, OpenWrt, Buildroot, Yocto, or other musl sshd boxes facing the internet and you are not sure which image actually got the restart, get a second set of eyes on the inventory. Book a slot with Dark Edge Consulting.

sources