This is a bad lock on a side door that only exists in houses with a very unusual key system
CVE-2026-35414 is an OpenSSH authorization flaw affecting versions before 10.3. It lives in the uncommon path where sshd trusts a user CA key inside ~/.ssh/authorized_keys using cert-authority plus a principals="..." restriction, and that principals list contains more than one allowed principal. If the trusted CA will issue a certificate whose principal name contains a comma, OpenSSH can mis-match the certificate principals and accept a principal the attacker was not meant to have.
Vendor MEDIUM 4.2 is technically defensible, but operationally it is still too hot for most enterprises. The decisive friction is that this does not hit the main certificate-auth path (TrustedUserCAKeys with AuthorizedPrincipalsFile), and exploitation also requires the attacker to already possess a certificate from a CA the target account explicitly trusts in authorized_keys. That combination makes this a niche authenticated/post-trust edge case, so it scores LOW for patch-priority even though the local impact could be serious on the few hosts that use this pattern.
4 steps from start to impact.
Find a host using per-user SSH CA trust
authorized_keys contains a cert-authority entry with a principals="a,b"-style multi-principal restriction. This is the vulnerable path described by OpenSSH; hosts using TrustedUserCAKeys plus AuthorizedPrincipalsFile are outside scope. Weaponized tooling is just normal OpenSSH auth plumbing in sshd(8).- Target runs OpenSSH earlier than 10.3
- Target uses certificate auth via
cert-authoritylines inauthorized_keys - That line includes
principals=with more than one principal
- Most enterprises using SSH certs centralize trust with
TrustedUserCAKeys, which OpenSSH says is not affected - Internet scanners cannot reliably see per-user
authorized_keyscontent
Obtain a CA-signed certificate with a comma-bearing principal
ssh-keygen -s or the organization's CA issuance workflow.- Attacker can request or obtain a cert from the trusted CA
- CA policy allows the needed principal encoding
- Certificate includes a comma-bearing principal that collides with allowed principals
- Typical CAs strongly constrain which principals they issue
- Many enterprises gate SSH certificate issuance through tightly controlled identity workflows
- This prerequisite already implies prior trust or a CA-process failure
Authenticate with standard ssh client flow
sshd, which evaluates the authorized_keys principals="..." restriction using the incorrect matching algorithm. Because of the comma-handling bug, a certificate principal can be accepted as if it matched an allowed principal it should not match. Weaponized tooling is simply the stock ssh client with the issued cert.- Network reachability to SSH
- A valid CA-signed user certificate
- A vulnerable matching path in
sshd
- High attack complexity: several niche conditions must all line up
- No user interaction, but also no drive-by path
Land as the wrong account
authorized_keys trusted the CA line. Blast radius is constrained to the specific accounts and hosts that use this pattern; it is not a generic pre-auth remote code execution. Post-login impact then depends on local sudo, shell access, and host role.- Mis-match grants access to a meaningful target account
- That account has useful local privileges or lateral value
- No direct code execution from the bug itself
- Per-account trust boundaries sharply limit fleet-wide blast radius
sshd auth logs for certificate logins where the certificate principal set does not make sense for the accessed account; EDR only helps after login.The supporting signals.
| In-the-wild status | No public active exploitation evidence found in the sources reviewed, and the CVE is not KEV-listed. |
|---|---|
| Proof-of-concept availability | No authoritative public exploit repo confirmed from primary sources reviewed; the GitHub advisory shows "No known source code". |
| EPSS | Extremely low. Your intel lists 0.00031; GitHub Advisory currently shows about 0.022% / 6th percentile, which is directionally the same: low exploitation probability. |
| KEV status | Not listed in CISA KEV as of this assessment. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:N — the important parts are High attack complexity and Low privileges required, which translate in practice to *already-trusted attacker with a very specific cert-auth setup*. |
| Affected versions | OpenSSH < 10.3 per OpenSSH release notes and NVD. |
| Unaffected auth path | OpenSSH states the main certificate-authentication path using TrustedUserCAKeys and AuthorizedPrincipalsFile is not affected. This matters more than the raw CVSS number. |
| Fixed versions / backports | Upstream fix is 10.3 / 10.3p1. Examples of distro backports: Ubuntu 24.04 LTS fixed in 1:9.6p1-3ubuntu13.16, Ubuntu 22.04 LTS fixed in 1:8.9p1-3ubuntu0.15, Debian bookworm fixed in 1:9.2p1-2+deb12u10, Debian bullseye fixed in 1:8.4p1-5+deb11u7. |
| Scanning / exposure reality | Hard to census from outside. Shodan/Censys can fingerprint SSH exposure, but this bug depends on per-user authorized_keys contents and CA issuance policy, which are not externally observable. Treat external exposure counts as a poor proxy. |
| Reporter | Reported by Vladimir Tokarev in the OpenSSH 10.3 release notes / oss-security announcement. |
noisgate verdict.
The single biggest downgrade factor is that exploitation requires a trusted SSH certificate issuance path plus a rare per-user authorized_keys CA configuration, not just an exposed SSH port. This is a narrow, post-trust authorization bug with poor external reachability and limited blast radius across real enterprise fleets.
Why this verdict
- Requires prior trust, not raw reachability: the attacker needs a certificate from a CA the target account already trusts, which is a major downgrade from a pre-auth remote bug.
- Hits a niche config branch: OpenSSH says the common
TrustedUserCAKeys/AuthorizedPrincipalsFilepath is not affected; only CA keys trusted via per-userauthorized_keysare. - Needs a fragile chain of conditions: vulnerable version, multi-principal
principals=restriction, CA issuance behavior that permits comma-bearing principal values, and a useful target account all must line up. - Blast radius is account-scoped: compromise lands where that specific
authorized_keystrust exists, not broadly across every SSH listener on the host. - Telemetry and exploit economics are poor for attackers: the vulnerable condition is hard to discover remotely and hard to weaponize at scale, which aligns with the very low EPSS.
Why not higher?
This is not a pre-auth RCE, not a mass-exploitable parser bug, and not even a generic SSH-certificate flaw. The affected population is narrowed by internal configuration choices and CA issuance policy, which compounds the friction well beyond what a vendor CVSS label captures.
Why not lower?
It is still a real authorization bypass, and on the hosts that use this pattern it can authenticate an attacker as the wrong account. If one of those accounts is privileged, the local outcome can be severe even though the exposed population is small.
What to do — in priority order.
- Hunt for
cert-authorityplus multi-principalprincipals=lines — Search userauthorized_keysfiles forcert-authorityentries that also carryprincipals="a,b"-style restrictions. This identifies the tiny subset that is actually exposed; for a LOW verdict, do this as backlog hygiene with no SLA. - Prefer central CA trust paths — Where possible, move SSH certificate authorization to
TrustedUserCAKeyswithAuthorizedPrincipalsFileorAuthorizedPrincipalsCommand, which OpenSSH states is not affected by this bug. For a LOW verdict, make this part of normal hardening backlog hygiene. - Constrain CA issuance policy — Review the SSH CA workflow so it cannot mint unexpected principal values, especially comma-bearing or multi-value principal encodings that create parser edge cases. Do this during routine identity-control review, not as an emergency change.
- Log certificate principal details — Increase visibility around SSH certificate serials, principals, and target account mappings so misuse of unusual cert contents is easier to spot. For LOW, roll this into the next logging/telemetry tuning cycle.
- A WAF does nothing here; this is SSH authentication logic, not HTTP.
- Closing public SSH exposure alone is not a full answer, because the bug is just as relevant on internal admin networks if the niche cert-auth pattern exists.
- Version-only internet scanning overstates risk; seeing
OpenSSH_9.xon port 22 does not tell you whether the vulnerableauthorized_keystrust model is in use.
Crowdsourced verification payload.
Run this on the target Linux host as root so it can inspect system and user authorized_keys files. Save as check-cve-2026-35414.sh and run sudo bash check-cve-2026-35414.sh; it returns VULNERABLE when it finds both an unfixed version and a risky cert-authority + multi-principal principals= pattern, PATCHED when the installed package/version is known fixed, and UNKNOWN otherwise.
#!/usr/bin/env bash
# check-cve-2026-35414.sh
# Best-effort detector for CVE-2026-35414 on Linux/OpenSSH hosts.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
status="UNKNOWN"
reason=""
version_src=""
version_val=""
fixed_by_pkg=0
vuln_by_version=0
risky_cfg=0
have_cmd() { command -v "$1" >/dev/null 2>&1; }
log() { printf '%s\n' "$*"; }
# Try package-manager-aware fixed-version checks first for common Debian/Ubuntu cases.
check_dpkg_fixed() {
have_cmd dpkg-query || return 1
local pkgver=""
pkgver=$(dpkg-query -W -f='${Version}\n' openssh-server 2>/dev/null || true)
if [ -z "$pkgver" ]; then
pkgver=$(dpkg-query -W -f='${Version}\n' openssh-client 2>/dev/null || true)
fi
[ -z "$pkgver" ] && return 1
version_src="dpkg"
version_val="$pkgver"
# Known fixed distro package versions from vendor advisories.
if dpkg --compare-versions "$pkgver" ge '1:10.3p1-1'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:10.2p1-2ubuntu3.2'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:10.0p1-5ubuntu5.4'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:9.6p1-3ubuntu13.16'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:8.9p1-3ubuntu0.15'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:9.2p1-2+deb12u10'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:8.4p1-5+deb11u7'; then fixed_by_pkg=1; return 0; fi
if dpkg --compare-versions "$pkgver" ge '1:10.0p1-7+deb13u3'; then fixed_by_pkg=1; return 0; fi
vuln_by_version=1
return 0
}
extract_upstream_version() {
local raw="$1"
# Extract things like 9.6p1, 10.2, 10.3p1 from package or ssh -V output.
printf '%s' "$raw" | sed -nE 's/.*OpenSSH[_ ]([0-9]+\.[0-9]+(p[0-9]+)?).*/\1/p; t; s/.*([0-9]+\.[0-9]+(p[0-9]+)?).*/\1/p'
}
ver_ge_10_3() {
# Returns 0 if version >= 10.3, else 1. Handles forms like 10.3, 10.3p1, 9.9p2.
local v="$1"
local major minor
major=$(printf '%s' "$v" | sed -E 's/^([0-9]+)\..*/\1/')
minor=$(printf '%s' "$v" | sed -E 's/^[0-9]+\.([0-9]+).*/\1/')
[ -z "$major" ] && return 1
[ -z "$minor" ] && return 1
if [ "$major" -gt 10 ]; then return 0; fi
if [ "$major" -lt 10 ]; then return 1; fi
[ "$minor" -ge 3 ]
}
check_raw_version() {
local raw=""
if have_cmd ssh; then
raw=$(ssh -V 2>&1 | head -n1)
elif have_cmd sshd; then
raw=$(sshd -V 2>&1 | head -n1)
fi
[ -z "$raw" ] && return 1
version_src="binary"
version_val="$raw"
local up
up=$(extract_upstream_version "$raw")
[ -z "$up" ] && return 1
if ver_ge_10_3 "$up"; then
fixed_by_pkg=1
else
vuln_by_version=1
fi
return 0
}
scan_authorized_keys() {
local files=()
local f
# Common global and root locations
[ -f /root/.ssh/authorized_keys ] && files+=(/root/.ssh/authorized_keys)
[ -f /etc/ssh/authorized_keys ] && files+=(/etc/ssh/authorized_keys)
# Enumerate local users with home directories
if [ -r /etc/passwd ]; then
while IFS=: read -r _ _ _ _ _ home shell; do
[ -n "$home" ] || continue
[ -d "$home/.ssh" ] || continue
[ -f "$home/.ssh/authorized_keys" ] && files+=("$home/.ssh/authorized_keys")
[ -f "$home/.ssh/authorized_keys2" ] && files+=("$home/.ssh/authorized_keys2")
done < /etc/passwd
fi
for f in "${files[@]}"; do
[ -r "$f" ] || continue
if grep -Eqi 'cert-authority' "$f" && grep -Eqi 'principals="[^"]*,[^"]*"' "$f"; then
risky_cfg=1
reason="Found cert-authority with multi-principal principals= in $f"
return 0
fi
done
return 0
}
# Main
check_dpkg_fixed || true
if [ "$fixed_by_pkg" -eq 0 ] && [ "$vuln_by_version" -eq 0 ]; then
check_raw_version || true
fi
scan_authorized_keys
if [ "$fixed_by_pkg" -eq 1 ]; then
status="PATCHED"
if [ -z "$reason" ]; then
reason="Installed package/version appears fixed (${version_src}: ${version_val})"
fi
printf '%s - %s\n' "$status" "$reason"
exit 0
fi
if [ "$vuln_by_version" -eq 1 ] && [ "$risky_cfg" -eq 1 ]; then
status="VULNERABLE"
if [ -z "$reason" ]; then
reason="Vulnerable version plus risky authorized_keys pattern detected"
else
reason="Vulnerable version (${version_src}: ${version_val}) and risky config: ${reason}"
fi
printf '%s - %s\n' "$status" "$reason"
exit 1
fi
status="UNKNOWN"
if [ "$vuln_by_version" -eq 1 ]; then
reason="Version appears vulnerable (${version_src}: ${version_val}) but no readable risky authorized_keys pattern was confirmed"
else
reason="Could not determine fixed status from package/version data"
fi
printf '%s - %s\n' "$status" "$reason"
exit 2
If you remember one thing.
authorized_keys cert-authority entries with multi-principal principals= restrictions; if you do not use that pattern, document the rationale and move on. For a LOW verdict, there is no noisgate mitigation SLA and no noisgate remediation SLA — treat this as backlog hygiene, validate exposure in your next auth-hardening review, and roll the actual OpenSSH or distro backport fix through the normal maintenance cycle rather than burning an out-of-band window.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.