Vulnerability DatabaseGHSA-hjwv-j52r-xcg7

GHSA-hjwv-j52r-xcg7: 
Ruby vulnerability analysis and mitigation

Patches

Fixed in net-ssh 8.1.1 and 7.3.9. Host keys on a @revoked line in known_hosts are now refused by every verifier, matching OpenSSH.

Workarounds

Upgrade. On older versions, remove the revoked key from every known_hosts file net-ssh reads, including the @revoked line itself, and use verify_host_key: :always so an unknown key is refused rather than added.

Summary

Net::SSH's known_hosts parser (Net::SSH::KnownHosts#keys_for) reads the OpenSSH @marker field but only special-cases @cert-authority. A line marked @revoked, which is the standard OpenSSH way to permanently retire a compromised host key, falls into the default branch and is loaded as a regular, trusted HostKeyEntries::PubKey pin. Every built-in host-key verifier (:always, :accept_new, and the default :accept_new_or_local_tunnel) then matches a server that presents exactly that revoked key and accepts it, even under the strictest verifier. A revoked key is one the operator already knows is compromised, and here it authenticates the host anyway. The revocation entry quietly turns into an authorization entry. OpenSSH's hostfile.c/check_host_key returns HOST_REVOKED for the same line and ssh(1) aborts with "Host key ... was revoked", and ssh_config(5) says keys on a @revoked line "must always be refused".

Details

  • Affected: every release that parses known_hosts markers, up to 8.1.0 and 7.3.8.
  • CWE-295 (Improper Certificate Validation; revocation status not checked).
  • CVSS 3.1: 7.4 HIGH, CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N. AC:H accounts for the attacker needing the revoked private key; since a key is revoked because it is compromised, AC:L (9.1) is arguable.

Reachability

This is a different bug from the repo's sibling advisory GHSA-vxj5-fg65-x765 (published 2026-10-04). That one covers the @cert-authority marker and a different sink, CertAuthority#matches_key? skipping principal and validity checks, and it was patched in 7.3.4 and 8.0.0.beta3. That fix did not touch @revoked. Before the fix, net-ssh had no handling of @revoked at all, so OpenSSH's "distrust this key" is silently inverted into "trust this key". Reachability is niche, and I want to be plain about it. A manual @revoked <host> <type> <blob> line has to already exist in a known_hosts file that net-ssh reads, and hand-written @revoked lines are an obscure OpenSSH mechanism that few operators use. Where such a line does exist, the holder of the revoked private key gets a reliable accept instead of the hard refusal OpenSSH would give.

Proof of concept

An attacker who possesses a revoked host private key and has a network position (MITM, DNS spoof, or control of the original compromised host) presents K_S during key exchange:

  1. lib/net/ssh/transport/session.rb:95-99 — transport connects; Algorithms#start runs KEX.
  2. lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb:103 (analogously kex/abstract5656.rb:53-54, kex/curve25519_sha256.rb, kex/diffie_hellman_group_exchange_sha1.rb) — source: server-controlled KEXDH_REPLY / KEXECDH_REPLY is parsed; result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key → attacker's revoked key object.
  3. lib/net/ssh/transport/kex/abstract.rb:48-49 — exchange_keys → verify_server_key(result[:server_key]).
  4. lib/net/ssh/transport/kex/abstract.rb:82 — sink entry: connection.host_key_verifier.verify(key: key, key_blob: blob, fingerprint: fingerprint, session: connection).
  5. lib/net/ssh/transport/session.rb:359-368 — select_host_key_verifier: :always → Verifiers::Always, nil (default) → AcceptNewOrLocalTunnel < AcceptNew < Always — all inherit the vulnerable Always#verify.
  6. lib/net/ssh/verifiers/always.rb:16 — host_keys = arguments[:session].host_keys → lib/net/ssh/transport/session.rb:108-113 → KnownHosts.search_for → lib/net/ssh/known_hosts.rb:163-171 → KnownHosts#keys_for.
  7. lib/net/ssh/known_hosts.rb:242-243 — line @revoked <host> <type> <keyblob> starts with @, so it is parsed with the marker: marker, hosts, type, key_content, comment = line.split(' '); marker == "@revoked".
  8. lib/net/ssh/known_hosts.rb:254-256 — type is supported (e.g. ssh-rsa, ssh-ed25519) and the host pattern matches (line 277-290 match, incl. * wildcards — a @revoked * org-wide revocation matches every host).
  9. The defect — lib/net/ssh/known_hosts.rb:265-270:
    keys <<
      if marker == "@cert-authority"
        HostKeyEntries::CertAuthority.new(raw_key, comment: comment)
      else
        HostKeyEntries::PubKey.new(raw_key, comment: comment)   # <-- "@revoked" lands here as a TRUSTED pin
      end
  10. lib/net/ssh/verifiers/always.rb:19-25 — found_key = host_keys.find { ... }; PubKey#matches_key? (lib/net/ssh/known_hosts.rb:31-33) compares ssh_type + to_blob → exact match with the revoked key.
  11. lib/net/ssh/verifiers/always.rb:32 + :56,65,70,75 — verify_certificate! guards each certificate constraint with entry.respond_to?(...); PubKey responds to none → all checks skipped.
  12. lib/net/ssh/verifiers/always.rb:34 — returns true. abstract.rb:82 is satisfied; the signature check (abstract.rb:107) succeeds because the attacker owns the revoked private key. Connection proceeds to userauth with a host the user explicitly distrusted. (AcceptNew's rescue HostKeyUnknown path in verifiers/accept_new.rb is not even needed — verification succeeded outright.)

Impact

Host authentication bypass that opens a full SSH MITM. The attacker can read and inject session plaintext (commands, output, uploaded data), capture credentials sent over password auth, and take over deploy-tool command channels, since Capistrano, Kamal, and sshkit all sit on net-ssh. A server the operator explicitly distrusted is accepted as the real host, so everything the user does over that connection is exposed.


Source: NVD

Related Ruby vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-hjwv-j52r-xcg7HIGH7.4
  • Ruby logoRuby
  • net-ssh
NoYesNov 08, 2026
GHSA-qcf4-j55x-72hvMEDIUM6.5
  • Ruby logoRuby
  • net-ssh
NoYesNov 08, 2026
GHSA-hjvq-xxqv-7jxhMEDIUM5.9
  • Ruby logoRuby
  • savon
NoYesNov 06, 2026
GHSA-57m8-w3r7-5p3wMEDIUM4
  • Ruby logoRuby
  • savon
NoYesNov 06, 2026
GHSA-6vgc-f9v5-8939MEDIUMN/A
  • Ruby logoRuby
  • metainspector
NoYesNov 06, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management