[Security] Receive window check rejects only exactly-zero credit — negative window enables unbounded buffering (CWE-400)
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 5.8k
- Forks
- 734
- PR merge metrics
- No merged PRs in 30d
Description
Summary
The ssh2 package for Node.js (tested: 1.17.0, ref 318d447ce3ac) does not correctly enforce its advertised SSH channel receive window. The inbound CHANNEL_DATA handler rejects data only when the remaining window is exactly zero, then subtracts the payload length regardless — a single oversized payload drives the window negative, after which every subsequent packet passes the guard and is buffered. Post-authentication memory-exhaustion DoS.
Affected version
ssh2 (npm), default branch, ref 318d447ce3ac (latest as of 2026-07).
Root cause
lib/client.js (CHANNEL_DATA handler):
if (channel.incoming.window === 0) // line 580: only EXACTLY zero
return;
channel.incoming.window -= data.length; // line 583: can go negative
if (channel.push(data) === false) { // line 585: buffered anyway
Client advertises MAX_WINDOW = 2 * 1024 * 1024 (2 MiB). The guard should be data.length > channel.incoming.window; once window goes negative, === 0 never matches again → unbounded buffering.
PoC (end-to-end)
[server] channel open; client advertised window = 2097152 bytes
[driver] child baseline VmRSS=60600 kB
[server] sent 18874368 bytes of CHANNEL_DATA (16777216 beyond advertised window)
[driver] child VmRSS peak=88784 kB (growth=28184 kB = 27.5 MiB)
[driver] VERDICT: CONFIRMED
Client advertised 2 MiB window; RSS grew 27.5 MiB while 16 MiB was pushed beyond window.
Suggested fix
if (data.length > channel.incoming.window)
return; // or disconnect
channel.incoming.window -= data.length;
Apply to both CHANNEL_DATA and CHANNEL_EXTENDED_DATA handlers.
CWE
CWE-400 (Uncontrolled Resource Consumption), post-authentication.
Credit
Reported by zhangph (afldl), 2026-07.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/client.js at the CHANNEL_DATA handler around lines 580-585, then inspect the CHANNEL_EXTENDED_DATA handler for the same receive-window logic. Verify the window check against payload length, cover oversized payloads and subsequent packets, and run the existing test suite to confirm that data beyond the advertised window is no longer buffered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100