GHSA-cqjc-rmpq-xprq Russh: Post-auth remote panic via pty-req with more than 130 terminal-mode records
SummaryA post-authentication denial-of-service panic in `russh` 0.62.2 (commit
`c4be19f1915c8682f4615c3fd50008512b474491`, current default branch `main` as
of 2026-07-22). An authenticated client sends a `pty-req` channel request
carrying more than 130 terminal-mode records. The parser uses a fixed
`[(Pty::TTY_OP_END, 0); 130]` array but increments its counter `i` for every
valid record (logging "too many pty codes" without returning), then slices
`&modes[0..i]` — an out-of-bounds slice that **panics** (`range end index 131
out of range for slice of length 130`) before the application `pty_request`
handler runs.This is reachable with the **default** server configuration and the **default**
crypto config (curve25519-sha256 + chacha20-poly1305), requiring only an
authenticated session channel — no caller-supplied parameter. It is reproduced
end-to-end against the unmodified real russh 0.62.2 library (a real
`russh::client` + `russh::server` over TCP, using the public
`Channel::request_pty(...)` API); the PoC below links the real crate, not a
copied snippet. The defect is still present on `main` HEAD (`v0.62.3`,
2026-07-22) and is not covered by any of the 11 published russh GHSA
advisories (GHSA-4r3c-5hpg-58qr / CVE-2026-48110 is allocation-first string
parsing, not the fixed-array slice overflow; it was fixed in 0.61.0 but this
code path still overflows the fixed array).Rust bounds-checked panics abort the task safely (no memory corruption / RCE);
the impact is remote **denial of service**.Details`russh/src/server/encrypted.rs`, `pty-req` handling (lines 1137–1201):Each terminal-mode record is exactly 5 bytes (1-byte opcode + 4-byte value),
and `i += 1` runs for **every** valid record (including repeats of the same
opcode). The `if i < 130` write-gate prevents an in-array overflow but the
counter still grows unbounded, and the later `&modes[0..i]` slice has no
corresponding bound. SSH packet-size limits do not bound the mode count to
130, so a single normal-sized `pty-req` can carry hundreds of mode records.
The client's own `request_pty` serialization (`russh/src/client/session.rs`:writes every record with no count cap, so 131 records reach the server as a
legitimate authenticated channel request.PoCThe PoC is a standalone `examples/` binary that links the **unmodified** real
russh 0.62.2 crate and reproduces over a real TCP connection with the default
crypto config. It runs an ATTACK case (131 mode records → panic) and a CONTROL
case (130 mode records → parses fine), proving the panic is caused
specifically by exceeding the 130-entry array.One-line reproducer`russh/examples/e2e_c15_pty_modes_panic.rs`Real captured output (ATTACK, `RUST_BACKTRACE=1`):The panic occurs in russh's own post-auth parser before any application
handler is invoked.Impact**Remote, post-authentication denial of service of any russh SSH server using
the default configuration.** Any authenticated client with a session channel can
crash the russh server task with a single `SSH_MSG_CHANNEL_REQUEST` `pty-req`
carrying 131+ terminal-mode records (each record is 5 bytes, so 131 records
fit in one normal-sized packet). This is trivially reachable for any legitimate
or compromised SSH user. DoS only — Rust bounds-checked panics abort the task
safely; there is no memory corruption or RCE.Suggested fixCap `i` at 130 and reject the request instead of logging and continuing:Affected versions`russh` **<= 0.62.3** (commit `c4be19f1915c` / current `main` HEAD
`v0.62.3`, 2026-07-22). The bug is still present on `main`; it is not covered
by any of the 11 published russh GHSA advisories. Default `server::Config`
and `client::Config` are affected (no feature flag or opt-in).CreditReported by the diff/ambidiff security research effort (afldl). Happy to
coordinate a disclosure timeline; will request a CVE once confirmed.
CVSS v3.1 score: 4.3