CVE-2026-128087: CVE-2026-128087: Premature Key Exchange Callback Invocation Prior to Host Key Verification in russh
CVE-2026-128087: Premature Key Exchange Callback Invocation Prior to Host Key Verification in russh Vulnerability ID: CVE-2026-128087 CVSS Score: 3.7 Published: 2026-11-13 CVE-2026-128087 (GHSA-9264-jvgf-6w2f) is an
CVE-2026-128087: Premature Key Exchange Callback Invocation Prior to Host Key Verification in russh
Vulnerability ID: CVE-2026-128087
CVSS Score: 3.7
Published: 2026-11-13
CVE-2026-128087 (GHSA-9264-jvgf-6w2f) is an incorrect behavior order (CWE-696) and improper authorization (CWE-863) vulnerability in the russh Rust SSH library, affecting versions 0.55.0 through 0.65.0. During the initial SSH key exchange (KEX) handshake, the client state machine invokes the client::Handler::kex_done() callbackβproviding the negotiated raw shared secret bytesβprior to validating the remote server's host key or certificate via check_server_key(). Consequently, an untrusted or rogue SSH server can complete cryptographic key agreement and force a connecting client to execute side-effecting application logic inside kex_done() before the server's identity is checked and rejected.
TL;DR
In russh versions 0.55.0 through 0.65.0, the client::Handler::kex_done() callback is invoked with the raw SSH shared secret before check_server_key() verifies the remote server's identity. Applications using kex_done() to initialize secondary channels or process shared secrets can be forced to interact with an unauthenticated server. Fixed in version 0.65.1.
Technical Details
- CVE / Advisory ID: CVE-2026-128087 / GHSA-9264-jvgf-6w2f
- Weakness Class: CWE-696 (Incorrect Behavior Order) / CWE-863 (Incorrect Authorization)
- Affected Component: russh crate (russh::client::Handler::kex_done)
- CVSS v3.1 Score: 3.7 Low (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N)
- EPSS Score: 0.24% (15.05th Percentile)
- Impact: Premature shared secret callback execution against unauthenticated SSH servers
- Exploit & KEV Status: No known public exploits; Not listed in CISA KEV
- Patched Version: russh >= 0.65.1
Affected Systems
- russh (Rust crate versions >= 0.55.0, < 0.65.1)
-
russh: >= 0.55.0, < 0.65.1 (Fixed in:
0.65.1)
Code Analysis
Commit: 43a46d6
Ensure client::Handler::kex_done() runs only after check_server_key() during the initial SSH key exchange.
File: russh/src/client/mod.rs
@@ -2033,14 +2033,11 @@ async fn reply<H: Handler>(
session.common.strict_kex =
session.common.strict_kex || newkeys.names.strict_kex();
- // Call the kex_done handler before consuming newkeys
- let shared_secret = newkeys.kex.shared_secret_bytes();
- handler
- .kex_done(shared_secret, &newkeys.names, session)
- .await?;
-
if session.common.encrypted.is_some() {
// This is a rekey
+ handler
+ .kex_done(newkeys.kex.shared_secret_bytes(), &newkeys.names, session)
+ .await?;
{
let common = &mut session.common;
common.newkeys(newkeys);
@@ -2077,6 +2074,10 @@ async fn reply<H: Handler>(
}
}
+ handler
+ .kex_done(newkeys.kex.shared_secret_bytes(), &newkeys.names, session)
+ .await?;
+
session
.common
.encrypted(initial_encrypted_state(session), newkeys);
@@ -2812,6 +2813,11 @@ pub trait Handler: Sized + Send {
/// Called when key exchange has completed.
///
+ /// For the initial key exchange this runs only after
+ /// [`check_server_key`](Self::check_server_key) has accepted the server,
+ /// so the shared secret never reaches the application for a server that
+ /// is about to be rejected.
+ ///
/// This callback provides access to the raw shared secret from the KEX,
/// which is useful for protocols that derive additional keys from the
/// SSH shared secret (e.g., for secondary encrypted channels).
Mitigation Strategies
- Upgrade the russh crate dependency to version 0.65.1 or later to enforce host key verification prior to kex_done() invocation.
- Defer side-effecting operations, secondary channel initialization, and out-of-band transmissions using kex_done() key material until after check_server_key() or client authentication succeeds.
- Ensure custom implementations of check_server_key() perform synchronous or properly awaited validation before returning Ok(true).
Remediation Steps:
- Update Cargo.toml to specify russh = ">= 0.65.1".
- Execute 'cargo update -p russh' to refresh the Cargo.lock file to the patched release.
- Review custom implementations of the russh::client::Handler trait in the codebase to audit how kex_done() and check_server_key() interact.
- Recompile and redeploy all affected Rust binaries and services.
References
- GitHub Security Advisory: GHSA-9264-jvgf-6w2f
- Fix Commit 43a46d67a80a7355fcd2fb25e7e00d79aec8184c
- russh Pull Request #808
- russh Release v0.65.1
- NVD Detail: CVE-2026-128087
- CVE.org Record: CVE-2026-128087
- CVEListV5 JSON Record: CVE-2026-128087
- Wiz Vulnerability Database: CVE-2026-128087
- Red Hat Customer Portal: CVE-2026-128087
Read the full report for CVE-2026-128087 on our website for more details including interactive diagrams and full exploit analysis.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.