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

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]