CVE-2026-46673
Russh: Unchecked CryptoVec allocation and growth handling is reachable from local agent inputs in current russh releases and from remote SSH traffic in historical pre-0.58.0 releases
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
Russh: Unchecked CryptoVec allocation and growth handling is reachable from local agent inputs in current russh releases and from remote SSH traffic in historical pre-0.58.0 releases
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
- Record
CVE-2026-46673- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
EUVDEUVD-2026-36124
7.5
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
- Record
EUVD-2026-36124- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-g9f8-wqj9-fjw5
7.5
Russh: Unchecked CryptoVec allocation and growth handling is reachable
Title
Unchecked CryptoVec allocation and growth handling was reachable from local agent inputs in current russh releases and from remote SSH traffic in historical pre-0.58.0 releases
Summary
CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers.
Details
The underlying unsafe paths were in CryptoVec:
cryptovec/src/cryptovec.rs- unchecked capacity growth
- unchecked length arithmetic in growth callers
- raw allocation and reallocation paths coupled to those sizes
cryptovec/src/platform/unix.rsmlock/munlockpreviously accepted zero-length calls and performed null-pointer validation inside theunsafeOS-call path
There are two relevant reachability stories:
- current local reachability in
russh
russh/src/keys/agent/client.rsAgentClient::read_response()read a peer-suppliedu32length and then resizedself.bufto that value before reading the payload
russh/src/keys/agent/server.rsConnection::run()read a peer-suppliedu32length and then resizedself.bufto that value before reading the payload
This is the path that still existed in current 0.60.x releases before the fix, although by then those buffers were no longer CryptoVec.
- historical remote reachability in older
russh
- before commit
712e32b(first released inv0.58.0), non-secret transport and compression buffers inrusshstill usedCryptoVec - I verified this in a detached pre-
712e32bworktree by adding and running:cipher::tests::remote_packet_length_grows_transport_cryptovec_buffercompression::tests::remote_compressed_payload_expands_cryptovec_output
- those tests show that remote SSH traffic could grow
CryptoVecthrough:- transport packet reads
- zlib decompression output
Also added a constrained-memory reproduction in that historical worktree:
compression::tests::remote_compressed_payload_can_crash_under_memory_limit
That test re-execs the test binary under prlimit --as=134217728, decompresses a highly compressible payload that expands to 96 MiB, and reliably aborts in the old Unix CryptoVec path when NonNull::new_unchecked() receives a null pointer after allocation failure.
The prepared patch does two things:
-
hardens
CryptoVecitself- checked capacity growth
- checked length arithmetic
- immediate allocation-failure handling
- zero-length
mlock/munlockno-ops - explicit null-pointer validation before entering the Unix
unsafelocking calls
-
hardens the real untrusted-input path
- caps agent frame lengths at
256 * 1024on both client and server before resizing buffers
- caps agent frame lengths at
This cap matches OpenSSH’s agent framing guardrail.
PoC
The following end-to-end tests demonstrate the real untrusted-input path by feeding oversized peer-controlled agent frame lengths into the public client and server flows and asserting that they are rejected before buffer growth.
Client-side agent reply path:
#[test]
fn oversized_agent_response_is_rejected_before_allocation() -> std::io::Result<()> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(async {
let (mut writer, reader) = tokio::io::duplex(64);
let server = tokio::spawn(async move {
let mut frame = [0u8; 4];
writer.read_exact(&mut frame).await?;
let len = BigEndian::read_u32(&frame) as usize;
let mut body = vec![0; len];
writer.read_exact(&mut body).await?;
BigEndian::write_u32(&mut frame, (MAX_AGENT_FRAME_LEN + 1) as u32);
…
- Record
GHSA-g9f8-wqj9-fjw5- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
NVD
7.5
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
- Record
CVE-2026-46673- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSV
7.5
Russh: Unchecked CryptoVec allocation and growth handling is reachable from local agent inputs in current russh releases and from remote SSH traffic in historical pre-0.58.0 releases
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
- Record
CVE-2026-46673- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-46673
7.5
Russh is a Rust SSH client & server library. Prior to version 0.60.3, CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers. This issue has been patched in version 0.60.3.
- Record
DEBIAN-CVE-2026-46673- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVGHSA-g9f8-wqj9-fjw5
7.5
Russh: Unchecked CryptoVec allocation and growth handling is reachable
Title
Unchecked CryptoVec allocation and growth handling was reachable from local agent inputs in current russh releases and from remote SSH traffic in historical pre-0.58.0 releases
Summary
CryptoVec used unchecked capacity growth, unchecked length arithmetic, and unsafe allocation/locking paths. In current russh releases, local SSH agent peers could still feed attacker-controlled frame lengths into buffer growth before validation. In older russh releases before 0.58.0, remote SSH traffic also reached CryptoVec through transport and compression buffers.
Details
The underlying unsafe paths were in CryptoVec:
cryptovec/src/cryptovec.rs- unchecked capacity growth
- unchecked length arithmetic in growth callers
- raw allocation and reallocation paths coupled to those sizes
cryptovec/src/platform/unix.rsmlock/munlockpreviously accepted zero-length calls and performed null-pointer validation inside theunsafeOS-call path
There are two relevant reachability stories:
- current local reachability in
russh
russh/src/keys/agent/client.rsAgentClient::read_response()read a peer-suppliedu32length and then resizedself.bufto that value before reading the payload
russh/src/keys/agent/server.rsConnection::run()read a peer-suppliedu32length and then resizedself.bufto that value before reading the payload
This is the path that still existed in current 0.60.x releases before the fix, although by then those buffers were no longer CryptoVec.
- historical remote reachability in older
russh
- before commit
712e32b(first released inv0.58.0), non-secret transport and compression buffers inrusshstill usedCryptoVec - I verified this in a detached pre-
712e32bworktree by adding and running:cipher::tests::remote_packet_length_grows_transport_cryptovec_buffercompression::tests::remote_compressed_payload_expands_cryptovec_output
- those tests show that remote SSH traffic could grow
CryptoVecthrough:- transport packet reads
- zlib decompression output
Also added a constrained-memory reproduction in that historical worktree:
compression::tests::remote_compressed_payload_can_crash_under_memory_limit
That test re-execs the test binary under prlimit --as=134217728, decompresses a highly compressible payload that expands to 96 MiB, and reliably aborts in the old Unix CryptoVec path when NonNull::new_unchecked() receives a null pointer after allocation failure.
The prepared patch does two things:
-
hardens
CryptoVecitself- checked capacity growth
- checked length arithmetic
- immediate allocation-failure handling
- zero-length
mlock/munlockno-ops - explicit null-pointer validation before entering the Unix
unsafelocking calls
-
hardens the real untrusted-input path
- caps agent frame lengths at
256 * 1024on both client and server before resizing buffers
- caps agent frame lengths at
This cap matches OpenSSH’s agent framing guardrail.
PoC
The following end-to-end tests demonstrate the real untrusted-input path by feeding oversized peer-controlled agent frame lengths into the public client and server flows and asserting that they are rejected before buffer growth.
Client-side agent reply path:
#[test]
fn oversized_agent_response_is_rejected_before_allocation() -> std::io::Result<()> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(async {
let (mut writer, reader) = tokio::io::duplex(64);
let server = tokio::spawn(async move {
let mut frame = [0u8; 4];
writer.read_exact(&mut frame).await?;
let len = BigEndian::read_u32(&frame) as usize;
let mut body = vec![0; len];
writer.read_exact(&mut body).await?;
BigEndian::write_u32(&mut frame, (MAX_AGENT_FRAME_LEN + 1) as u32);
…
- Record
GHSA-g9f8-wqj9-fjw5- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSVRUSTSEC-2026-0153
7.5
Unchecked `CryptoVec` allocation and growth handling
CryptoVec used unchecked capacity growth, unchecked length arithmetic, and
unsafe allocation and locking paths. In affected russh releases,
attacker-controlled input could reach these code paths through buffer resizing
operations.
Two affected reachability paths were identified:
-
Current
russhreleases (0.60.xbefore the fix) Local SSH agent peers could provide attacker-controlled frame lengths that were used to resize internal buffers before validation in:AgentClient::read_responseagent::server::Connection::run
-
Historical
russhreleases before0.58.0CryptoVecwas also used for non-secret transport and compression buffers, allowing remote SSH traffic to triggerCryptoVecgrowth through:- transport packet reads
- zlib decompression output
These remote paths were removed in 0.58.0 when CryptoVec stopped being used
for those buffers.
Under constrained memory conditions, historical russh versions prior to
0.58.0 can abort the process when remote compressed payload expansion causes
allocation failure in CryptoVec. This was reproduced through the compression
path and resulted in process termination in the Unix allocation/locking
implementation after null pointer allocation failure.
For current affected releases, oversized local SSH agent frame lengths could trigger untrusted-input-driven buffer growth prior to validation.
No practical remote code execution, integrity or confidentiality impact has been demonstrated.
Fixed by validating CryptoVec growth operations and rejecting oversized SSH agent frame lengths before buffer allocation.
- Record
RUSTSEC-2026-0153- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVRUSTSEC-2026-0154
7.5
Unbounded 32-bit allocation
Both the SSH agent server and client accepted peer-controlled frame lengths without enforcing a maximum frame size. This could cause large memory allocations while parsing a maliciously crafted agent frame.
A malicious peer could advertise an oversized frame length, causing the client or server to attempt a large memory allocation before validating the frame, potentially leading to memory exhaustion or process termination.
This is fixed by enforcing a maximum agent frame size of 256 KiB and rejecting oversized frames before buffer allocation.
- Record
RUSTSEC-2026-0154- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
russh-cryptoveccrates.io |
through 0.60.2 | 0.60.3 |
russhcrates.io |
through 0.60.2 | 0.60.3 |
rust-russhDebian:14 |
before 0.64.1-1, plus listed versions 0.57.1-10.57.1-2 |
0.64.1-1 |
rust-russh-cryptovecDebian:14 |
before 0.62.0-1, plus listed versions 0.52.0-10.58.0-10.59.0-1 |
0.62.0-1 |
russh-cryptoveccrates.io |
before 0.60.3 | 0.60.3 |
russhcrates.io |
before 0.60.3 | 0.60.3 |
russh-cryptoveccrates.io |
0.0.0-0 up to 0.60.3 | 0.60.3 |
russhcrates.io |
0.0.0-0 up to 0.60.3 | 0.60.3 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-46673 is a high vulnerability (CVSS 7.5) in Eugeny Russh, published May 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.26%, the 18th percentile. Fixed in russh-cryptovec 0.60.3.
References
github.com/Eugeny/russh/security/advisories/GHSA-g9f8-wqj9-fjw5
rustsec.org/advisories/RUSTSEC-2026-0153.html
rustsec.org/advisories/RUSTSEC-2026-0154.html
nvd.nist.gov/vuln/detail/CVE-2026-46673
github.com/advisories/GHSA-g9f8-wqj9-fjw5
github.com/CVEProject/cvelistV5/tree/main/cves/2026/46xxx/CVE-2026-46673.json
Left out here: the rest of 2 source descriptions. The JSON record has them.