Summary
Russh improperly accepts SSH channel lifecycle events for identifiers that the client did not open, establish, or still own. A malicious SSH server may trigger application panics or corrupt command completion and exit-code tracking when these events reach public client callbacks.
Affected context
The issue occurs in Russh client handling after authentication, when inbound channel data, lifecycle events, or selected request subtypes are forwarded to application callbacks without verifying channel ownership and state. It is relevant when an application connects to an untrusted or compromised SSH server and relies on callback state for command completion, exit status, or channel lifecycle management.
Exploit preconditions
- Attack surface: SSH client protocol message handling
- Required access: The attacker must operate or control an SSH server that the client connects to, or otherwise be able to send authenticated server-side protocol messages
- Trigger point: Receipt of channel data, channel lifecycle events, or
exit-status,exit-signal, andxon-xoffrequests - Why exploitation is possible: Incoming messages are forwarded to public callbacks without confirming that the referenced channel identifier belongs to an opened and established client channel
Why this happens
The underlying bug is insufficient validation of protocol state and resource ownership. Russh processes channel-related messages based on a supplied ChannelId without first confirming that the identifier represents a valid, client-created, currently established channel. This maps to CWE-20 because externally supplied protocol values are accepted without enforcing the expected range, lifecycle, and ownership constraints, allowing invalid state transitions to reach application logic.
Potential impact
- A malicious server may cause a client application to panic
- Command completion handling may become inconsistent or incorrect
- Exit codes or signal state may be corrupted
- Applications may lose reliable tracking of channel lifecycle events
- Repeated malformed events could cause denial of service
General mitigation guidance
Mitigation generally focuses on validating channel ownership and lifecycle
state before dispatching protocol events to application callbacks.
Common defensive patterns include:
- Accepting channel events only for identifiers associated with established client channels
- Rejecting or safely ignoring messages for unopened, unconfirmed, or released channels
- Making callback dispatch resilient to invalid state transitions
- Treating remote protocol fields as untrusted and validating them at the parsing boundary
- Avoiding panics for malformed or unexpected peer input
- Limiting client privileges and isolating SSH sessions according to least-privilege principles
- Using maintained library revisions that contain the relevant validation behavior
How teams detect issues like this
Organizations can look for this class of issue through:
- Static analysis and code review checks for callback dispatch based solely on remote identifiers
- Tests that send channel events for unknown, predicted, duplicate, closed, and released identifiers
- State-machine testing of SSH channel creation, confirmation, closure, and event ordering
- Fuzzing protocol handlers with invalid channel identifiers and unexpected lifecycle sequences
- Runtime monitoring for repeated panics, callback failures, or inconsistent command exit-state records
- Dependency and policy checks that flag outdated cryptographic or protocol libraries

