Back to Intelligence

CVE-2026-123158 (SSHole): OpenSSH Empty-Password Login Flaw Exploited Within Hours — Detection and Remediation Guide

SA
Security Arsenal Team
November 6, 2026
12 min read

If your organization runs OpenSSH on musl libc-based Linux systems — think Alpine Linux containers, embedded appliances, minimal Docker images, and IoT-adjacent infrastructure — you are already inside the exploitation window. According to Previdian, threat actors began attempting exploitation of CVE-2026-123158, codenamed SSHole, within hours of public disclosure. Researchers observed attackers successfully gaining root access on a honeypot built to observe the flaw's exploitation.

This is not a theoretical exercise. CVSS 8.1, confirmed in-the-wild exploitation, and a trivial attack condition — the ability to sign in to accounts that have no password set — combine into exactly the kind of vulnerability that gets folded into botnet scanners and initial-access toolkits before most change-control boards have even seen the advisory. The speed of weaponization here is the story: the gap between disclosure and exploitation has collapsed to hours, and your detection and patching posture needs to assume that any exposed, vulnerable sshd was probed the same day this went public.

Technical Analysis

What Is Affected

CVE-2026-123158 impacts Linux systems running OpenSSH under a very specific but surprisingly common combination:

  • C library: musl libc (the default on Alpine Linux and widely used in minimal container base images, embedded systems, and network appliances)
  • Authentication stack: OpenSSH built or deployed without Pluggable Authentication Modules (PAM) support — i.e., UsePAM no or a build compiled without PAM

Alpine's popularity as a container base image is what makes this dangerous at scale. Any internet-exposed service built FROM alpine with sshd layered on top for remote administration or debugging is a candidate target. Embedded and OT/IoT Linux distributions built on musl with stripped-down authentication stacks are equally exposed and are far less likely to be in your patch pipeline.

How the Vulnerability Works

From a defender's perspective, the mechanics matter because they tell you exactly what to hunt for. On affected builds, the interaction between musl libc's handling of empty password fields and OpenSSH's non-PAM authentication path allows authentication to succeed against accounts whose password field is empty rather than locked.

The critical distinction:

  • A locked account (! or * in /etc/shadow) correctly rejects all password authentication.
  • An empty password field (nothing between the colons in /etc/shadow) should fail closed — OpenSSH's PermitEmptyPasswords no default exists precisely for this. On vulnerable musl/non-PAM builds, that control fails open: the empty password comparison succeeds and the session is granted.

Attack chain observed and inferred:

  1. Reconnaissance: Internet-wide scanning for SSH banners on port 22 (and non-standard ports), fingerprinting Alpine/musl-based targets.
  2. Authentication bypass: SSH connection attempts against accounts with empty password fields — root being the highest-value target. On vulnerable systems, the authentication succeeds with no credential material at all. In logs this surfaces as an Accepted none or anomalous Accepted password event for an account that has no password configured.
  3. Post-exploitation: Interactive shell as the compromised account — root in the observed honeypot compromise — followed by the standard playbook: persistence (authorized_keys injection, new accounts), payload staging, and lateral movement.

Exploitation Status

  • Active exploitation: CONFIRMED. Previdian observed exploitation attempts within hours of disclosure and a successful root compromise of a honeypot.
  • Weaponization trajectory: Given the trivial exploitation requirements (no credentials, no user interaction, no race condition), expect rapid integration into automated SSH scanning and botnet recruitment infrastructure.
  • Exposure surface: Any sshd reachable from an untrusted network on a musl-based, non-PAM build. Do not assume internal-only SSH is safe — this is equally valuable for lateral movement once an attacker has any foothold.

The operational implication: treat every vulnerable, network-reachable sshd as potentially already compromised and scope your IR accordingly. Honeypot root access within hours tells you the scanning infrastructure was staged before or immediately at disclosure.

Detection & Response

The highest-fidelity detections for SSHole exploitation live in the authentication logs. You are looking for two things: (1) successful SSH authentication events that should be impossible — Accepted none authentication, or successful auth for accounts with empty or locked password fields — and (2) host-level indicators of a vulnerable configuration: musl libc, sshd running with PAM disabled, and empty password fields in /etc/shadow.

Sigma Rules

YAML
---
title: SSH Accepted None Authentication - Possible CVE-2026-123158 SSHole Exploitation
id: 3f8a1c92-7d44-4e5b-9a21-6c0d2e8f5a17
status: experimental
description: Detects SSH sessions accepted with the 'none' authentication method, which is a strong indicator of empty-password authentication bypass attempts against OpenSSH builds affected by CVE-2026-123158 (SSHole) on musl libc systems without PAM. Legitimate sshd configurations should never complete 'none' authentication.
references:
  - https://thehackernews.com/2026/11/hackers-exploited-openssh-sshole-flaw.html
  - https://attack.mitre.org/techniques/T1078/
author: Security Arsenal
date: 2026/11/05
tags:
  - attack.initial_access
  - attack.t1078
  - attack.t1021.004
logsource:
  product: linux
  service: sshd
detection:
  selection:
    - 'Accepted none for'
  condition: selection
falsepositives:
  - Extremely rare; misconfigured or deliberately insecure test SSH servers
level: critical
---
title: Successful SSH Login to Root or Service Account From External Source
id: 8b2e5d41-1a6f-4c93-b7e0-9d4f3a6c1e28
status: experimental
description: Detects successful SSH password authentication for root or common service accounts. In the context of CVE-2026-123158, attackers gained root on honeypots via empty-password accounts. Any 'Accepted password' for root on a system where root has no password set or is locked is a high-confidence compromise indicator.
references:
  - https://thehackernews.com/2026/11/hackers-exploited-openssh-sshole-flaw.html
  - https://attack.mitre.org/techniques/T1021.004/
author: Security Arsenal
date: 2026/11/05
tags:
  - attack.initial_access
  - attack.persistence
  - attack.t1021.004
logsource:
  product: linux
  service: sshd
detection:
  selection:
    - 'Accepted password for root'
    - 'Accepted password for admin'
    - 'Accepted password for alpine'
    - 'Accepted password for nobody'
  condition: selection
falsepositives:
  - Environments that legitimately permit root SSH login (itself a finding worth escalating)
level: high
---
title: Interactive Shell Spawned by SSHD Followed by Persistence Activity
id: 5c1d9f06-2e8b-4a71-c3d4-7f0a5b9e2d36
status: experimental
description: Detects common post-exploitation behavior following SSH access consistent with SSHole (CVE-2026-123158) compromises - shell spawned by sshd writing SSH authorized_keys or creating user accounts for persistence.
references:
  - https://thehackernews.com/2026/11/hackers-exploited-openssh-sshole-flaw.html
  - https://attack.mitre.org/techniques/T1098.004/
  - https://attack.mitre.org/techniques/T1136.001/
author: Security Arsenal
date: 2026/11/05
tags:
  - attack.persistence
  - attack.t1098.004
  - attack.t1136.001
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/sshd'
  selection_cmd:
    CommandLine|contains:
      - 'authorized_keys'
      - 'useradd '
      - 'adduser '
      - 'addgroup '
      - '/etc/shadow'
      - 'chmod 600'
  condition: selection_parent and selection_cmd
falsepositives:
  - Legitimate administrative SSH sessions performing account management
  - Configuration management tooling (Ansible, cloud-init) operating over SSH
level: high

KQL (Microsoft Sentinel / Defender)

For most enterprises, sshd telemetry lands in Sentinel via Syslog/CEF ingestion from Linux hosts and container nodes. This query hunts the core SSHole exploitation pattern — impossible or anomalous successful authentications — and correlates them with post-authentication session activity.

KQL — Microsoft Sentinel / Defender
// Hunt for SSHole (CVE-2026-123158) exploitation indicators in sshd Syslog telemetry
// Focus: 'Accepted none' auth (empty-password bypass) and successful auth to root/service accounts
let Lookback = 14d;
let SuspiciousAuth = Syslog
    | where TimeGenerated > ago(Lookback)
    | where ProcessName =~ "sshd"
    | where SyslogMessage has "Accepted"
    | extend AuthMethod = extract(@"Accepted (\S+) for", 1, SyslogMessage),
             Account = extract(@"Accepted \S+ for (\S+)", 1, SyslogMessage),
             SourceIP = extract(@"from ([0-9a-fA-F\.:\%]+)", 1, SyslogMessage)
    | where AuthMethod == "none"
       or (AuthMethod == "password" and Account in~ ("root", "admin", "alpine", "nobody", "daemon"));
SuspiciousAuth
| join kind=leftouter (
    Syslog
    | where TimeGenerated > ago(Lookback)
    | where ProcessName =~ "sshd"
    | where SyslogMessage has "session opened"
    | extend SessionAccount = extract(@"user (\S+)", 1, SyslogMessage)
) on $left.Account == $right.SessionAccount
| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),
            AuthEvents = count(), AuthMethods = make_set(AuthMethod),
            SourceIPs = make_set(SourceIP), Hosts = make_set(Computer)
  by Account
| extend Severity = iif(AuthMethods has "none", "CRITICAL - Possible SSHole bypass", "HIGH - Verify account password state")
| order by FirstSeen asc;

For teams ingesting process telemetry from Defender for Endpoint on Linux, layer in post-exploitation hunting:

KQL — Microsoft Sentinel / Defender
// Post-exploitation: shells under sshd executing persistence or recon commands
let Lookback = 14d;
DeviceProcessEvents
| where TimeGenerated > ago(Lookback)
| where InitiatingProcessFileName has "sshd"
| where FileName in~ ("useradd", "adduser", "usermod", "chpasswd", "curl", "wget", "base64")
   or ProcessCommandLine has_any ("authorized_keys", "/etc/shadow", "/etc/passwd", "chmod 600")
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
| order by TimeGenerated desc;

Velociraptor VQL

This hunt artifact does two jobs at once: it identifies hosts that are vulnerable (musl libc, sshd without PAM, empty password fields) and surfaces active compromise indicators (established SSH sessions from unexpected sources). Run it across your Linux fleet — especially container hosts, Alpine-based nodes, and embedded infrastructure.

VQL — Velociraptor
-- SSHole (CVE-2026-123158) exposure and compromise hunt
-- 1) Identify accounts with EMPTY password fields (the exploitation precondition)
-- 2) Check sshd config for PAM disabled
-- 3) Enumerate established SSH connections for unexpected peers

LET passwd = SELECT Line FROM parse_lines(filename='/etc/shadow')
LET empty_pw = SELECT split(string=Line, sep=':')[0] AS User,
       split(string=Line, sep=':')[1] AS PasswordField
FROM passwd
WHERE PasswordField = ''

LET sshd_config = SELECT grok(data=Line,
  grok='(?i)^\\s*(UsePAM|PermitEmptyPasswords|PermitRootLogin)\\s+(\\S+)',
  attributes=['Directive', 'Value']) AS Parsed
FROM parse_lines(filename='/etc/ssh/sshd_config')
WHERE Parsed

LET ssh_sessions = SELECT Laddr, Raddr, State, Name AS Process
FROM netstat()
WHERE Name =~ 'sshd' AND State = 'ESTABLISHED'

SELECT 'empty_password_account' AS Finding, User AS Detail, '' AS Extra FROM empty_pw
UNION ALL
SELECT 'sshd_config' AS Finding, Parsed.Directive AS Detail, Parsed.Value AS Extra FROM sshd_config
UNION ALL
SELECT 'active_ssh_session' AS Finding, format(format='%v -> %v', args=[Laddr.IP, Raddr.IP]) AS Detail, State AS Extra FROM ssh_sessions

Any empty_password_account finding on an internet-reachable musl host is an emergency. Any UsePAM no combined with an empty password field is the exact vulnerable configuration — treat the host as compromised until proven otherwise.

Remediation and Verification Script

Use this Bash script to assess exposure, apply compensating controls, and verify remediation across your Linux estate. It is safe to run read-only first; the hardening section requires root.

Bash / Shell
#!/bin/bash
# CVE-2026-123158 (SSHole) assessment and hardening script
# Run as root. Test in staging before broad deployment.

set -u
echo "=== SSHole (CVE-2026-123158) Exposure Assessment ==="

# 1) Check for musl libc (glibc systems are not affected by this specific flaw)
echo "[1] C library check:"
if ldd --version 2>&1 | grep -qi musl; then
    echo "    [!] musl libc DETECTED - system is in the affected class"
    MUSL=1
else
    echo "    [+] glibc/other libc detected - not affected by CVE-2026-123158"
    MUSL=0
fi

# 2) Check sshd PAM configuration
echo "[2] sshd PAM configuration:"
USEPAM=$(sshd -T 2>/dev/null | grep -i '^usepam' | awk '{print $2}')
if [ "$USEPAM" = "no" ]; then
    echo "    [!] UsePAM is DISABLED - vulnerable configuration if musl=1"
else
    echo "    [+] UsePAM: ${USEPAM:-unknown (check build flags)}"
fi

# 3) Find accounts with EMPTY password fields (the exploitation precondition)
echo "[3] Accounts with empty password fields:"
EMPTY=$(awk -F: '($2 == "") {print $1}' /etc/shadow)
if [ -n "$EMPTY" ]; then
    echo "    [!] CRITICAL - empty passwords found for: $EMPTY"
else
    echo "    [+] No empty password fields found"
fi

# 4) Check PermitEmptyPasswords and PermitRootLogin effective config
echo "[4] sshd effective auth controls:"
sshd -T 2>/dev/null | grep -iE '^(permitemptypasswords|permitrootlogin|passwordauthentication)'

# 5) HARDENING (uncomment to apply)
echo "[5] Applying compensating controls..."
# Lock every account with an empty password field
for acct in $EMPTY; do
    passwd -l "$acct" 2>/dev/null && echo "    [+] Locked account: $acct"
done
# Enforce safe sshd directives
cat >> /etc/ssh/sshd_config.d/99-sshole-hardening.conf <<'EOF'
PermitEmptyPasswords no
PermitRootLogin no
PasswordAuthentication no
UsePAM yes
EOF
sshd -t && echo "    [+] sshd config valid - restart sshd to apply: systemctl restart sshd"

# 6) Check for signs of prior exploitation
echo "[6] Reviewing auth logs for 'Accepted none' events:"
grep -h "Accepted none" /var/log/auth.log /var/log/secure /var/log/messages 2>/dev/null | tail -20
journalctl -u sshd --since "14 days ago" 2>/dev/null | grep "Accepted none" | tail -20

echo "=== Assessment complete. Any 'Accepted none' events above indicate likely compromise - initiate IR. ==="

Remediation

Prioritize by exposure: internet-facing musl/Alpine systems first, then internal container infrastructure and embedded devices, then everything else running sshd.

  1. Patch OpenSSH immediately. Apply the fixed OpenSSH packages from your distribution. On Alpine, run apk upgrade openssh and confirm the installed version includes the CVE-2026-123158 fix per the Alpine security tracker. Verify the running sshd binary was actually replaced — containers must be rebuilt from patched base images, not patched in place; a running container keeps the vulnerable sshd until redeployed.

  2. Rebuild with PAM where feasible. The vulnerable condition specifically requires PAM to be disabled. Builds of OpenSSH compiled with PAM support and running UsePAM yes are not affected by this flaw. Where you control the build (embedded, custom images), enable PAM.

  3. Eliminate empty password fields — this is the exploitation precondition. Audit /etc/shadow fleet-wide for empty password fields (awk -F: '$2=="" {print $1}' /etc/shadow) and lock every one (passwd -l). This is a durable compensating control even before patching: no empty password, no bypass.

  4. Enforce safe sshd configuration. Set PermitEmptyPasswords no, PermitRootLogin no, and preferably PasswordAuthentication no (key-only auth) everywhere. Validate with sshd -T to confirm effective configuration, not just config file contents.

  5. Reduce exposure. SSH should never be internet-exposed without compensating controls. Move administrative SSH behind VPN/bastion hosts, apply source-IP allowlisting via firewall or Match Address blocks, and disable sshd entirely in container images unless there is a documented operational need — which there rarely is; use kubectl exec / docker exec instead.

  6. Hunt before you assume clean. Given confirmed exploitation within hours of disclosure, review at least 14 days of sshd authentication logs for Accepted none events and successful password auth to root/service accounts on vulnerable hosts. Any hit means full IR scoping: check ~/.ssh/authorized_keys for unauthorized keys, review new accounts, inspect outbound connections, and consider credential rotation for anything the host could reach.

  7. Inventory the musl estate. Many organizations cannot answer "where do we run Alpine with sshd?" — fix that now. Query your container registry for Alpine-based images including openssh, sweep embedded/OT asset inventories, and tag these assets for expedited patching. If Alpine devices cannot be patched (vendor-controlled firmware), isolate them behind ACLs and monitor aggressively.

The defensive lesson extends past this CVE: disclosure-to-exploitation timelines of hours mean your patch SLA for internet-facing, trivially exploitable services must be measured in the same units. Honeypots getting popped for root same-day is the warning shot — assume your scanners' targets are someone else's too.

Related Resources

Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.