Vulnerability DatabaseCVE-2026-128087

CVE-2026-128087: 
Rust vulnerability analysis and mitigation

Overview

CVE-2026-128087 is a callback ordering vulnerability in the russh Rust SSH client/server library, where client::Handler::kex_done() is invoked with the raw key-exchange shared secret before check_server_key() verifies the server's host key or certificate. This affects russh versions >= 0.55.0 and < 0.65.1, introduced when the kex_done callback was added in commit 500bef1. The vulnerability was published on November 3, 2026, and assigned a CVSS v3.1 base score of 3.7 (Low) (Github Advisory, Feedly).

Technical details

The root cause is an incorrect behavior order (CWE-696) combined with incorrect authorization (CWE-863) and key exchange without entity authentication (CWE-322). In russh/src/client/mod.rs, the library calls kex_done() immediately after the server proves cryptographic possession of its presented host key, but before the application's check_server_key() callback decides whether that key belongs to the intended server. Because any attacker-controlled SSH server can produce a valid KEX signature with its own key, cryptographic verification of the KEX does not establish peer identity — only check_server_key() does. Applications that override kex_done() to derive secondary channel keys, initialize VPN-over-SSH transports, or perform other protocol-bridging actions are therefore exposed to premature callback execution by a rogue server (Github Advisory, russh PR #808).

Impact

An unauthenticated attacker who can impersonate or intercept the SSH endpoint targeted by a vulnerable russh client can trigger the application's kex_done() callback — and any secondary-channel initialization or key derivation it performs — before the connection is rejected via UnknownKey. The practical impact depends entirely on the application's callback implementation: applications using kex_done() for VPN-over-SSH, UDP data planes, file transfer, or custom enterprise transports may expose early secondary-channel data or establish state with an untrusted peer. Confidentiality is the primary concern (low impact per CVSS); integrity and availability are not directly affected. Clients that leave kex_done() at its no-op default are not affected (Github Advisory).

Exploitability

A self-contained proof-of-concept (PoC) written in Rust is publicly available in the GitHub Security Advisory, demonstrating that kex_done() fires before check_server_key() rejects an untrusted host key (Github Advisory). The PoC is classified as poc_code with high confidence by Feedly's exploit analysis, though it only demonstrates the ordering bug against a local server and does not compromise a real system. Exploitation requires the attacker to control or impersonate the SSH endpoint the client connects to (high attack complexity), and the client application must override kex_done() with security-sensitive logic. There is no evidence of in-the-wild exploitation, no threat actor attribution, and the EPSS score is 0.0. The vulnerability is not listed in the CISA KEV catalog (Feedly).

Exploitation steps

  1. Identify a target: Locate a russh client application (versions 0.55.0–0.65.0) that overrides client::Handler::kex_done() to perform security-sensitive actions such as deriving secondary channel keys or initializing a VPN/data-plane transport.
  2. Set up a rogue SSH server: Deploy a malicious SSH server with a self-generated Ed25519 host key (not trusted by the target client). This can be done using russh itself or any SSH server implementation.
  3. Intercept or redirect the client connection: Use DNS spoofing, ARP poisoning, BGP hijacking, or another network-level technique to redirect the target client's SSH connection to the rogue server.
  4. Complete the key exchange: Allow the SSH handshake to proceed normally. The rogue server produces a valid KEX signature with its own host key, satisfying the cryptographic proof-of-possession check.
  5. Trigger premature callback: The vulnerable russh client invokes kex_done() with the raw shared secret before calling check_server_key(). Any application logic in kex_done() — such as exporting the shared secret or initializing a secondary channel — executes at this point.
  6. Observe the outcome: The connection ultimately fails with russh::Error::UnknownKey when check_server_key() rejects the rogue host key, but the attacker has already triggered the application's callback and any associated side effects (Github Advisory).

Indicators of compromise

  • Network: Unexpected SSH connection attempts to unknown or newly observed server IP addresses from russh-based client applications; SSH handshakes that complete KEX but terminate immediately with a key rejection error.
  • Logs: Application logs showing kex_done callback execution followed immediately by a connection failure or UnknownKey error; SSH client logs indicating repeated connection attempts to endpoints with unrecognized host keys.
  • Process/Application Behavior: Secondary channel initialization (e.g., VPN tunnel setup, UDP data plane activation) occurring transiently before a connection is fully established and then torn down; unexpected outbound connections on secondary protocol ports initiated by the russh client process shortly before SSH connection failure.

Mitigation and workarounds

Upgrade russh to version 0.65.1 or later, which fixes the ordering bug by moving the kex_done() call to after check_server_key() has accepted the server identity for the initial key exchange (russh v0.65.1 Release, russh PR #808). The fix was merged in commit 43a46d6. As a short-term workaround for applications that cannot immediately upgrade, developers should audit their kex_done() implementations and add an independent server identity check within the callback before taking any security-sensitive action, or defer all callback-derived actions until host trust is confirmed through another mechanism (Github Advisory).

Community reactions

The vulnerability was reported by researcher Yeaseen and published by the russh maintainer (Eugeny) on November 3, 2026, with the fix merged the same day via PR #808. The maintainer acknowledged and merged the fix promptly, noting the security fix in the v0.65.1 release notes alongside several other bug fixes (russh v0.65.1 Release). No significant broader media coverage or notable community debate has been identified beyond the advisory and associated pull request.

Additional resources

Linux Distribution fix status

Fix availability across major Linux distributions and their releases.

RHEL / CentOS

Unknown

Source: This report was generated using AI

Related Rust vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-xxg2-76qg-7vj6MEDIUMN/A
  • Rust logoRust
  • kule
NoYesNov 13, 2026
GHSA-xgh6-8m9v-7xr8LOWN/A
  • Rust logoRust
  • kule
NoYesNov 13, 2026
GHSA-rfw3-44wh-p22wLOWN/A
  • Rust logoRust
  • kule
NoYesNov 13, 2026
GHSA-r8fh-9r4w-rf4qMEDIUMN/A
  • Rust logoRust
  • kule
NoYesNov 13, 2026
GHSA-p82p-rwwx-7ghwMEDIUMN/A
  • Rust logoRust
  • kule
NoYesNov 13, 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