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.
Summary
The
ssh2package for Node.js (tested: 1.17.0, ref318d447ce3ac) does not correctly enforce its advertised SSH channel receive window. The inboundCHANNEL_DATAhandler 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):Client advertises
MAX_WINDOW = 2 * 1024 * 1024(2 MiB). The guard should bedata.length > channel.incoming.window; once window goes negative,=== 0never matches again → unbounded buffering.PoC (end-to-end)
Client advertised 2 MiB window; RSS grew 27.5 MiB while 16 MiB was pushed beyond window.
Suggested fix
Apply to both
CHANNEL_DATAandCHANNEL_EXTENDED_DATAhandlers.CWE
CWE-400 (Uncontrolled Resource Consumption), post-authentication.
Credit
Reported by zhangph (afldl), 2026-07.