Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 271/271 feeds/APIs · 464/464 docs · 8/9 advisories · checked 23:08 UTC Customize Public modeDiscuss ChangeIntel on Discord

Russh: client wrong-length X25519 `clone_from_slice` panic (pre-auth DoS)

Collected exploitation and prediction evidence

Risk source coverage

CISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.

No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.

cve-program · CVE-2026-73429

Published

Russh is a Rust SSH client & server library. Prior to 0.62.4, a malicious SSH server can crash a russh client session with a malformed KEX_ECDH_REPLY containing a server ephemeral value that is not 32 bytes long. The client-side Curve25519Kex::compute_shared_secret function in russh/src/kex/curve25519.rs passes the decoded exchange.server_ephemeral value to clone_from_slice without validating its length, causing a deterministic panic before the server host key is verified. The panic terminates the spawned client session task and surfaces as a JoinError, while the embedding process normally remains running. This issue is fixed in version 0.62.4.

Source published
12 Aug 2026 20:53:19 UTC
Source modified
14 Aug 2026 22:15:45 UTC
Observed here
23 Oct 2026 15:48:27 UTC
Source terms
CVE Program Terms of Use

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · 5.3 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

nvd · CVE-2026-73429

Published

Russh is a Rust SSH client & server library. Prior to 0.62.4, a malicious SSH server can crash a russh client session with a malformed KEX_ECDH_REPLY containing a server ephemeral value that is not 32 bytes long. The client-side Curve25519Kex::compute_shared_secret function in russh/src/kex/curve25519.rs passes the decoded exchange.server_ephemeral value to clone_from_slice without validating its length, causing a deterministic panic before the server host key is verified. The panic terminates the spawned client session task and surfaces as a JoinError, while the embedding process normally remains running. This issue is fixed in version 0.62.4.

NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.

Source analysis status: Deferred

Weakness classifications: CWE-704 · CWE-754

Original publisher date fields

published: 2026-08-12T21:17:41.750

lastModified: 2026-10-24T15:10:00.190

Source published
12 Aug 2026 21:17:41 UTC
Source modified
24 Oct 2026 15:10:00 UTC
Observed here
25 Oct 2026 15:19:09 UTC
Source terms
NIST NVD usage terms; underlying source attribution retained

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · [email protected] · Secondary · 5.3 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

osv · GHSA-g9hv-x236-4qp3

Published

### Summary A malicious SSH server can crash a `russh` client session with a single malformed key-exchange reply, causing a pre-authentication Denial-of-Service before the server host key is verified. The embedding process itself stays up, but the connection is killed deterministically. ### Details Every *other* kex path in `russh` validates the peer ephemeral length before cloning: - `Curve25519Kex::server_dh` (`russh/src/kex/curve25519.rs:61-65`) checks `if pubkey_len != 32 { return Err(crate::Error::Kex); }` before `clone_from_slice`. - The hybrid ML-KEM, ECDH-NIST, and DH/GEX paths all validate lengths. Only the client-side curve25519 `compute_shared_secret` is missing the check. This asymmetric validation gap makes the bug easy to miss in code review: a malicious *client* cannot panic a `russh` server this way (the server path checks the length), but a malicious *server* can panic a `russh` client. Incriminated source code (repo-relative paths): - Vulnerable `compute_shared_secret`: `russh/src/kex/curve25519.rs:110-117` (panic at line 113) - Client-side entry point: `russh/src/client/kex.rs:266-277` (`KEX_ECDH_REPLY` → `Bytes::decode` → `compute_shared_secret`) - Server-side contrast (has the length check): `russh/src/kex/curve25519.rs:51-88` (`server_dh`) - Session spawn site: `russh/src/client/mod.rs` (`connect_stream` → `russh_util::runtime::spawn`) - Runtime wrapper: `russh-util/src/runtime.rs:37-48` (`spawn` wraps `tokio::spawn`; panic surfaces as `JoinError`) ### PoC A standalone, self-contained Cargo PoC is provided in `vuln_poc/vuln_002_client_wronglen_x25519_panic/` in this repo. It installs a global panic hook that sets an `AtomicBool` if any panic fires, starts a malicious raw SSH server on `127.0.0.1:0` that completes the SSH id and `KEXINIT` exchange, reads the client `KEX_ECDH_INIT`, and sends `KEX_ECDH_REPLY` with a 16-byte server ephemeral (instead of 32) and a fake signature. It then calls `russh::client::connect` with `Preferred::kex` set to `curve25519-sha256` and a handler that accepts any server key (the check is never reached because the client panics first) and prints a clear verdict. Build & run: ```bash cd vuln_poc/vuln_002_client_wronglen_x25519_panic cargo run --release ``` Expected output (verdict line, from a successful reproduction): ``` [poc] panic captured: panicked at russh/src/kex/curve25519.rs:113:25: copy_from_slice: source slice length (16) does not match destination slice length (32) [!] Vulnerability reproduced: russh client panicked in Curve25519Kex::compute_shared_secret on a wrong-length (16-byte) server ephemeral before verifying the host key signature (pre-auth client DoS). ``` The malicious payload is the `f` field of `KEX_ECDH_REPLY`: ``` MSG_KEX_ECDH_REPLY (1 byte, value 0x1f) string K_S (server host key blob — any valid-looking bytes) string f (server ephemeral — 16 bytes of 0x00 instead of 32) string signature (fake; never verified by the client) ``` The length prefix of `f` is `4` (u32 BE) = 16, followed by 16 bytes. The `russh` client decodes this into `exchange.server_ephemeral` (a `Vec<u8>` of length 16) and passes it to `compute_shared_secret`, which panics on `clone_from_slice`. ### Impact **What kind of vulnerability:** CWE-704 (incorrect type conversion / cast — `clone_from_slice` length mismatch) → deterministic panic → pre-authentication per-connection Denial-of-Service. The attacker does not need the server's private key; any network position that can deliver a malformed `KEX_ECDH_REPLY` (a rogue server, or a MitM before authentication) suffices. **Who is impacted:** any deployment that uses `russh::client::connect` (or `connect_stream`) to connect to an attacker-controlled or MitM-reachable SSH server, and that negotiates `curve25519-sha256` (the default and most-preferred kex algorithm in `russh`). A single malformed `KEX_ECDH_REPLY` kills the client session; the attack is deterministic and single-packet. The panic is isolated to the spawned session task (`tokio::spawn` catches it and surfaces a `JoinError`), so the embedding process keeps running — the impact is per-connection DoS, not process crash, unless the embedder installs a custom panic hook that calls `std::process::abort`. **Workaround:** until a fix is released, clients can reduce exposure by disabling `curve25519-sha256` in the `Preferred::kex` list and preferring a kex algorithm whose peer-ephemeral length is validated (e.g. the ECDH-NIST or DH/GEX paths). This is a mitigation, not a fix. **Suggested fix (one-line length check, mirrors the existing server-side `server_dh` check):** ```rust // russh/src/kex/curve25519.rs, at the top of compute_shared_secret: fn compute_shared_secret(&mut self, remote_pubkey_: &[u8]) -> Result<(), crate::Error> { if remote_pubkey_.len() != 32 { return Err(crate::Error::Kex); } let local_secret = self.local_secret.take().ok_or(crate::Error::KexInit)?; let mut remote_pubkey = MontgomeryPoint([0; 32]); remote_pubkey.0.clone_from_slice(remote_pubkey_); let shared = local_secret * remote_pubkey; self.shared_secret = Some(shared); Ok(()) } ``` This makes the client-side `compute_shared_secret` consistent with the existing server-side `server_dh` check at `russh/src/kex/curve25519.rs:61-65` and with the other kex paths that already validate peer ephemeral lengths. [vuln_poc.zip](https://github.com/user-attachments/files/29255207/vuln_poc.zip)

Source published
24 Jul 2026 16:47:16 UTC
Source modified
10 Sep 2026 03:50:52 UTC
Observed here
24 Oct 2026 13:19:54 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Publisher rating · MODERATE

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 25 Oct 23:08 UTC · 271 of 271 readable · 269 fully read · documentation 464/464 current