CVE-2026-105659: HTTP/2 blocked-send deadlines reset on every WINDOW_UPDATE, letting a trickle pin stream processes indefinitely in Bandit
Uncontrolled Resource Consumption vulnerability in mtrudel bandit allows an unauthenticated remote attacker to pin HTTP/2 stream processes indefinitely via a trickle of small WINDOWUPDATE frames. A stream whose response outruns the connection or stream send window blocks until the peer grants more window, and each block carries a 15 second deadline. Both deadlines restart whenever the peer makes partial progress. Bandit.HTTP2.Connection.finishdata/5 re-queues a partially advanced send in pendingsends with a fresh expiresat, so every WINDOWUPDATE on stream 0, and every SETTINGS frame, resets the clock. Bandit.HTTP2.Stream.senddata/3 recurses on each stream WINDOWUPDATE and re-arms a fresh after readtimeout. A peer that grants a few bytes every few seconds keeps the blocked stream process, its Plug state and any resource it holds mid-response alive for as long as it keeps dripping, and repeats this across streams and connections to exhaust server processes and memory.
The two paths are independent. The stream-level block is reached on its own by widening the connection window with a large WINDOWUPDATE on stream 0 and shrinking the per-stream window with a small SETTINGSINITIALWINDOWSIZE, so closing only the connection-level path leaves it exploitable.
This issue affects bandit: from 1.4.0 onward.
Affected Software
Event History
Frequently Asked Questions
Who can exploit this issue?
An unauthenticated remote peer that can establish an HTTP/2 connection to a Bandit server can exploit it. The attacker can repeat the behavior across streams and connections to consume server processes and memory.
What conditions are required to keep a server-side stream alive?
The server must be sending a response that outruns either the connection-level or stream-level send window, causing the send to block. The peer can then grant only a few bytes of window capacity every few seconds, making partial progress while repeatedly restarting the blocked-send deadline.
Are the connection-level and stream-level cases separate?
Yes. The two blocking paths are independent: connection-level blocking can be prolonged through WINDOW_UPDATE frames on stream 0 or SETTINGS frames, while stream-level blocking can be reached by widening the connection window and constraining the per-stream window with SETTINGS_INITIAL_WINDOW_SIZE.