CVE-2026-46702: russh · Post-decompression SSH packet size was not bounded, allowing remote oversized compressed packets
Affects russhSource GCVE Database
Not known to be exploited · CVSS 7.5 High : upgrade to 0.61.1 soon.
Data as of 10 Nov 2026, 20:05 UTC
- Patch
- Available – fixed in 0.61.1
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HExploitation evidence
Disclosed: evidence found.
CVE published 10 Jun 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponized: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 10 Nov 2026.
What to do
Upgrade russh to 0.61.1.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
| crates.iorussh | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
### Summary When SSH compression is enabled, `russh` accepted compressed packets whose on-wire size passed the normal transport packet-length checks but whose decompressed size was much larger. This allowed a remote peer to send oversized post-decompression packets that should have been rejected. In current releases, this is a remote denial-of-service / resource-exhaustion issue in the post-decompression receive path. In older releases before `0.58.0`, the same remote decompression path used `CryptoVec`, which appears to make the historical impact worse. ### Details The normal SSH transport read path enforces a packet-length limit before the packet body is read: - `russh/src/cipher/mod.rs` However, RFC 4253 compression is applied to the SSH `payload` field only. The `packet_length` field and MAC are computed over the compressed payload, so a packet that is reasonably sized on the wire can still expand to a much larger message body after decompression. In `russh`, compressed packet bodies are later decompressed in: - `russh/src/compression.rs` - `russh/src/client/mod.rs` - `russh/src/server/session.rs` Before the fix, `Decompress::decompress()` grew its output buffer by repeated doubling and did not enforce a separate post-decompression ceiling. That meant a peer could send a small compressed packet that passed the normal on-wire transport length checks and then inflate it into a much larger packet after decompression. It was verified that an attacker-crafted compressed payload can stay below the normal `256 KiB` implementation transport packet cap while still inflating above the intended post-decompression bound. In other words, this is not only a "large on-wire packet" issue. Version detail: - The underlying post-decompression bounds bug appears to affect `russh` as far back as `0.34.0`. - In historical releases `>= 0.34.0, < 0.58.0`, the remote decompression path still used `CryptoVec`. Remote compressed SSH traffic could drive that path, and under constrained memory that historical code path could abort the process. - In current-style releases `>= 0.58.0`, non-secret packet/decompression buffers were moved off `CryptoVec` and onto `Vec<u8>`, but the post-decompression size still remained unbounded. So the bug class remained reachable remotely, but the maintained-line impact is a current remote DoS / oversized-packet-acceptance issue rather than the older `CryptoVec`-based abort story. - The maintained-line fix was verified against `0.60.2`. Compression is not selected in a default-vs-default `russh` session because the default preference order puts `none` first. However, the default server configuration still advertises `zlib` and `zlib@openssh.com`, and server-side negotiation follows the client's preference order for common algorithms. A client that prefers compression can therefore negotiate it with a default `russh` server. OpenSSH portable was checked at `/home/mjc/projects/openssh-portable` commit `45b30e0a5`. OpenSSH enforces a `256 KiB` transport packet cap before decompression, but it does not reuse that cap after decompression. Instead, decompression writes to an `sshbuf`, which is indirectly bounded by OpenSSH's `SSHBUF_SIZE_MAX` hard maximum of `0x8000000` bytes (`128 MiB`). The patch direction should follow that model: add an explicit post-decompression ceiling of `128 MiB`, rather than assuming the compressed transport packet cap also bounds decompressed payload size. Relevant OpenSSH reference points: - `/home/mjc/projects/openssh-portable/packet.c`: `PACKET_MAX_SIZE (256 * 1024)` - `/home/mjc/projects/openssh-portable/packet.c`: `uncompress_buffer()` inflates into `compression_buffer` - `/home/mjc/projects/openssh-portable/sshbuf.h`: `SSHBUF_SIZE_MAX 0x8000000` ### RFC / OpenSSH Comparison RFC 4253 section 6 defines the binary packet format: - `packet_length` - `padding_length` - `payload` - random padding - MAC RFC 4253 section 6.2 says that, when compression is negotiated, the `payload` field is compressed, and that `packet_length` and MAC are computed from the compressed payload. The RFC also says implementations should check that packet length is reasonable to avoid denial-of-service and buffer-overflow attacks. That means the pre-decompression transport packet length check is necessary but not sufficient. A correct implementation still needs a reasonable bound on the decompressed payload that becomes parser input. OpenSSH provides such a bound indirectly through `sshbuf`'s hard maximum. The `russh` fix should make the corresponding post-decompression bound explicit. ### PoC There were two kinds of proof: - a wire-cap sanity test showing an attacker-crafted best-compressed `DEBUG` payload can stay below the normal SSH transport packet cap while still inflating beyond the intended post-decompression bound - direct client and server receive-path tests that exercise the oversized post-decompression behavior itself The current in-tree regression tests are: - `
References
- github.com/Eugeny/russh/security/advisories/GHSA-wwx6-x28x-8259 (opens in a new tab)
- nvd.nist.gov/vuln/detail/CVE-2026-46702 (opens in a new tab)
- github.com/Eugeny/russh/commit/2692a6f66edafaf63f463c412b45d8490f7ad06e (opens in a new tab)
- github.com/Eugeny/russh (opens in a new tab)
- github.com/Eugeny/russh/releases/tag/v0.61.1 (opens in a new tab)