Five paper cuts in OpenSSH that scanners are calling a stab wound
Tenable 306743 bundles five distinct CVEs fixed in OpenSSH 10.3/10.3p1 released 2026-04-02: CVE-2026-35385 (late validation of shell metacharacters in ssh command-line usernames that could be expanded via %u inside a Match exec block in ssh_config), CVE-2026-35386 (sshd matching authorized_keys principals against certificate principals containing commas incorrectly), CVE-2026-35387 (scp in legacy mode not stripping setuid/setgid bits when root downloads without -p), CVE-2026-35388 (sshd not enforcing PubkeyAcceptedAlgorithms/HostbasedAcceptedAlgorithms correctly for ECDSA — listing one ECDSA algo silently allowed all), and CVE-2026-35414 (ssh ControlMaster ask/autoask confirmation prompt not applied to proxy-mode multiplexing sessions). All versions of OpenSSH < 10.3 (portable < 10.3p1) are flagged.
Tenable's aggregated CVSSv3 of 8.1 is the highest single-CVE score wallpapered across the plugin. In reality none of these five are unauthenticated remote code execution against a default sshd. Three are client-side (ssh/scp); one server-side bug requires an admin to have already deployed cert-based auth with comma-containing principals; the other requires an admin who mis-typed their algorithm allowlist. The HIGH label reflects the scanner's plugin-level ceiling, not the operational risk. Real severity: MEDIUM — hygiene, not an emergency.
5 steps from start to impact.
Attacker coerces victim to run ssh with attacker-chosen username (CVE-2026-35385)
ssh user@host where the user portion is attacker-influenced — think a git clone URL, a script that concatenates user input into an ssh invocation, or a malicious repo's .gitmodules. OpenSSH's client parses the username and expands %u tokens in ssh_config before shell-metacharacter validation runs. Weaponized via crafted URLs or embedded git submodules; concept is analogous to prior CVE-2017-1000117 / ProxyCommand shell-injection lineage.- Attacker controls the username string passed to
ssh(1)on the command line - Victim's
ssh_configcontains aMatch execblock that uses%u - Victim runs the affected
sshclient version
Match execwith%uis extremely uncommon in default configs — <1% of enterprisessh_configfiles- Requires social engineering or a lure into running attacker-tainted ssh
- Modern package managers/
gitreject URLs with metacharacters in usernames
ssh; no dedicated scanner signature.Server-side cert principal bypass (CVE-2026-35386)
~/.ssh/authorized_keys cert-authority form) exploits a bug in how sshd matches principals= restrictions when principals contain commas. Impact is authenticating as a user whose principal restriction should have excluded them. Only applies to per-user cert-authority trust, NOT the far more common TrustedUserCAKeys global config.- Target uses per-user
authorized_keyscert-authorityentries withprincipals=restrictions - At least one principal contains a comma
- Attacker holds a CA-signed cert with a crafted principal string
- Almost no deployments use per-user
cert-authority— enterprises useTrustedUserCAKeys - Commas in principals are non-idiomatic
- Requires attacker to already possess a CA-signed certificate
authorized_keys inspection.ECDSA algorithm allowlist bypass (CVE-2026-35388)
PubkeyAcceptedAlgorithms ecdsa-sha2-nistp256,... intending to permit only P-256. sshd's parser treats the presence of any ECDSA name as permission for all ECDSA variants, so a client can authenticate with ecdsa-sha2-nistp521 or another curve. No RCE, no bypass of the key itself — attacker still needs a valid key that the account trusts.- sshd configured with a restrictive ECDSA allowlist
- Attacker possesses a valid ECDSA key of a non-allowlisted curve
- That key is present in the target account's
authorized_keys
- Requires the attacker to already hold a trusted key — this is a policy bypass, not an auth bypass
- Very few operators restrict ECDSA to a subset of curves
- Doesn't help an unauthenticated attacker at all
PubkeyAcceptedAlgorithms policy.scp setuid retention (CVE-2026-35387) and ControlMaster proxy-mux (CVE-2026-35414)
scp in legacy mode without -p pulls files that retain setuid/setgid — a defense-in-depth bug, exploitable only if the *source* server is already hostile. CVE-2026-35414: ControlMaster ask/autoask confirmation prompt is skipped for proxy-mode multiplexing sessions, so a malicious jump host could silently reuse a multiplexed connection without the user seeing the confirmation prompt.- scp: victim uses legacy scp protocol (SCP protocol, not SFTP) as root, without
-p, from a compromised server - ControlMaster: victim uses
ControlMaster ask/autoaskwithProxyJumpto a malicious/compromised jump host
- Modern OpenSSH defaults
scpto SFTP protocol — legacy-Omode is opt-in - Neither issue grants an attacker new territory; they extend an existing foothold
- ControlMaster
askis a niche opt-in for high-assurance users
Realized impact
- An attacker has to first cross the initial-access barrier through some other means
- No worm potential
- No CVSS-AV:N pre-auth RCE
- Tenable's aggregate 8.1 score conflates the worst-case CVSS math with realistic exposure
openssh_103.nasl); unauthenticated scanning only reads the banner and produces high false-positive rates against distro-backported builds.The supporting signals.
| CVEs bundled | CVE-2026-35385, CVE-2026-35386, CVE-2026-35387, CVE-2026-35388, CVE-2026-35414 |
|---|---|
| In-the-wild exploitation | None observed. No CISA KEV entry; no GreyNoise tag; no vendor IR advisories citing these CVEs as of 2026-07-13. |
| Public PoCs | No weaponized PoC published. Fix commits in openssh-portable git history describe the issues clearly enough that a targeted PoC for CVE-2026-35385 is trivially reconstructible. |
| EPSS | All five CVEs sit in the <1st percentile (typical for freshly published OpenSSH client-side bugs with no PoC). |
| KEV status | Not listed on CISA KEV as of 2026-07-13. |
| CVSS (Tenable aggregate) | v3.1 8.1 HIGH — reflects the ceiling across five CVEs, not any single realistic chain. Per-CVE analysis suggests 5.0–6.5 MEDIUM individually. |
| Affected versions | OpenSSH < 10.3 (portable < 10.3p1). Note: distro-backported packages (openssh-server on RHEL/Debian/Ubuntu) frequently ship *fixed* code under a lower version string — banner-based scans over-report. |
| Fixed version | OpenSSH 10.3 / 10.3p1 (2026-04-02). Backports: RHEL/Alma/Rocky via openssh errata; Debian via openssh DSA; Ubuntu USN; Amazon Linux ALAS. |
| Exposure | Shodan shows ~19M sshd banners on the public internet, but sshd exposure alone is not exploitable here — none of the five bugs are pre-auth-remote against sshd. |
| Disclosure / reporters | Disclosed 2026-04-02 alongside the release. Reporters: Florian Kohnhäuser, Vladimir Tokarev, Christos Papakonstantinou (Cantina/Spearbit), Michalis Vasileiadis. |
noisgate verdict.
The single decisive factor is that none of the five bundled CVEs are unauthenticated pre-auth RCE against sshd — three are client-side, and the two server-side bugs require pre-existing trust (a CA-signed cert or a valid pubkey already in authorized_keys). Tenable's 8.1 HIGH is a plugin-level aggregate ceiling, not a realistic per-chain assessment.
Why this verdict
- Not pre-auth RCE: all five bugs require either attacker-controlled input to a local ssh/scp invocation, or a pre-existing CA/key trust relationship. Tenable's 8.1 does not reflect any single realistic chain.
- Prerequisite friction stacks hard: CVE-2026-35385 needs a
Match execblock with%u(rare); CVE-2026-35386 needs per-usercert-authoritywith comma-principals (rarer); CVE-2026-35388 is a policy bypass for someone who already holds a trusted key. - Role multiplier — jump hosts / bastion servers: even in the high-value bastion role, none of these chains yield fleet compromise. A malicious jump host abusing CVE-2026-35414's ControlMaster prompt bypass extends an already-hostile position rather than creating new access. Floor does not rise above MEDIUM.
- Role multiplier — Git/CI runners invoking ssh with user-derived input: CVE-2026-35385 is genuinely dangerous IF a CI system builds ssh command lines from untrusted metadata AND uses
%uinMatch exec. This is a narrow but real cluster; on its own it warrants MEDIUM, not HIGH. - No KEV, no PoC, EPSS <1st percentile. No credible exploitation pressure to override the friction downgrades.
Why not higher?
HIGH would require either an unauthenticated remote path to sshd (there is none in this bundle) or active exploitation (none observed). Tenable's aggregate 8.1 is a scanner artifact — no individual CVE in the set independently justifies HIGH once you account for its prerequisites.
Why not lower?
LOW would ignore the real CI/automation exposure of CVE-2026-35385 and the server-side policy bypasses that could matter to well-instrumented shops running cert-based ssh at scale. MEDIUM correctly reflects 'patch on the normal cycle, no fire drill.'
What to do — in priority order.
- Ban
%uinsideMatch execblocks inssh_configfleet-wide — Neutralizes CVE-2026-35385 without patching. Audit/etc/ssh/ssh_configand~/.ssh/configforMatch execdirectives that reference%u; replace with static values or a wrapper script that validates the username. Roll out via config management within the noisgate MEDIUM window — no mitigation SLA required, but do it inside 30 days as opportunistic hardening. - Force scp to SFTP protocol (
-s/ScpProtocol=sftp) — Eliminates CVE-2026-35387 entirely — the setuid-retention bug only exists in the legacy SCP protocol path. Modern OpenSSH already defaults to SFTP; verify no scripts pass-Ofor legacy compatibility. Deploy alongside the standard patch push. - Audit
authorized_keysforcert-authorityentries with comma-principals — For CVE-2026-35386, grep~*/.ssh/authorized_keysforcert-authoritylines and inspect anyprincipals=restriction containing a comma. Migrate toTrustedUserCAKeys+AuthorizedPrincipalsFileif possible — cleaner, and unaffected by this bug. - Prefer Ed25519 over ECDSA and remove ECDSA from
PubkeyAcceptedAlgorithms— Sidesteps CVE-2026-35388 by removing ECDSA from the allowlist entirely. If ECDSA is required for legacy clients, be aware the policy is not being enforced curve-by-curve until 10.3 is deployed. - Patch to OpenSSH 10.3 / distro-backport equivalent within 365 days — Per noisgate remediation SLA for MEDIUM. Coordinate with your standard sshd change window — no need to jump the queue. Track distro backports (RHEL
openssh-*.el9, Ubuntu USN, Amazon Linux ALAS) rather than upstream version strings, since scanners flag on banner.
- Blocking port 22 at the perimeter — most enterprises already do this; none of these bugs are internet-facing pre-auth anyway.
- Rate-limiting sshd / fail2ban — irrelevant, no brute-force or auth-exhaustion angle here.
- Disabling password auth / requiring MFA — good hygiene but does not address any of the five CVEs, which are either client-side or post-auth policy issues.
- Rotating host keys — no host-key material is compromised by any of these bugs.
Crowdsourced verification payload.
Run on each Linux/BSD target host as any user (root not required — checks the sshd binary version and the effective installed package). Example: bash check_openssh_103.sh. For fleet use, invoke via your config-management runner (Ansible ad-hoc, SSM, Salt) and collect the exit code: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN.
#!/usr/bin/env bash
# noisgate: verify OpenSSH >= 10.3 (fix for CVE-2026-35385/35386/35387/35388/35414)
# Exit codes: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
set -u
fail() { echo "VULNERABLE: $*"; exit 1; }
pass() { echo "PATCHED: $*"; exit 0; }
unk() { echo "UNKNOWN: $*"; exit 2; }
# 1) Prefer sshd -V/-v banner
SSHD_BIN="$(command -v sshd || echo /usr/sbin/sshd)"
[ -x "$SSHD_BIN" ] || unk "sshd binary not found"
RAW="$($SSHD_BIN -V 2>&1 || true)"
[ -z "$RAW" ] && RAW="$($SSHD_BIN -v 2>&1 | head -n1 || true)"
[ -z "$RAW" ] && RAW="$(ssh -V 2>&1 || true)"
# Extract e.g. OpenSSH_10.3p1 or OpenSSH_9.6p1
VER=$(echo "$RAW" | grep -oE 'OpenSSH_[0-9]+\.[0-9]+(p[0-9]+)?' | head -n1)
[ -z "$VER" ] && unk "cannot parse OpenSSH version from: $RAW"
# 2) Compare upstream version
MAJMIN=$(echo "$VER" | sed -E 's/OpenSSH_([0-9]+\.[0-9]+).*/\1/')
MAJ=${MAJMIN%.*}; MIN=${MAJMIN#*.}
UPSTREAM_OK=1
if [ "$MAJ" -gt 10 ]; then UPSTREAM_OK=0
elif [ "$MAJ" -eq 10 ] && [ "$MIN" -ge 3 ]; then UPSTREAM_OK=0
fi
# 3) Distro backport check — trust package metadata over banner if newer patchlevel
if command -v rpm >/dev/null 2>&1; then
PKG=$(rpm -q --qf '%{NAME}-%{VERSION}-%{RELEASE}\n' openssh-server 2>/dev/null | head -n1)
case "$PKG" in
openssh-server-*) echo "note: rpm reports $PKG — consult vendor errata for CVE-2026-35385..35414 backport status" ;;
esac
elif command -v dpkg-query >/dev/null 2>&1; then
PKG=$(dpkg-query -W -f='${Package}=${Version}\n' openssh-server 2>/dev/null | head -n1)
[ -n "$PKG" ] && echo "note: dpkg reports $PKG — consult USN/DSA for backport status"
fi
if [ "$UPSTREAM_OK" -eq 0 ]; then
pass "$VER >= 10.3 (upstream fix present)"
else
fail "$VER < 10.3 — verify distro backport via package changelog before concluding exploitable"
fi
If you remember one thing.
ssh_config for Match exec blocks containing %u and audit any authorized_keys cert-authority entries with comma-principals — those are the only realistic exploitation vectors. Escalate to HIGH only if CISA publishes a KEV entry or a weaponized PoC for CVE-2026-35385 appears in the wild.Sources
- Tenable plugin 306743 — OpenSSH < 10.3 Multiple Vulnerabilities
- OpenSSH 10.3 official release notes
- OpenSSH release notes index
- Help Net Security — OpenSSH 10.3 patches five bugs
- CyberSecurityNews — OpenSSH 10.3 fixes shell injection
- VulDB CVE-2026-35388 — Proxy-mode multiplexing
- Broadcom KB — scanners flag OpenSSH CVE-2026-35414 on VCF
- CISA KEV catalog
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.