[Security] Receive window check rejects only exactly-zero credit — negative window enables unbounded buffering (CWE-400)

Open Beginner friendly
#1,505 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
74/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
javascript, node.js
Domain
security

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.

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.

Dominant language
JavaScript
Stars
5.8k
Forks
734
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from mscdex/ssh2

All issues in mscdex/ssh2

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.