Problem
DapFrameDecoder (src/proxy/dap-framing.ts:39-110) accepts any finite positive Content-Length with no upper bound (:96 rejects only null/≤0/non-finite). A peer advertising a huge frame makes rawData accumulate indefinitely until the "full frame" arrives — i.e. until OOM.
Exposure:
- Adapter side (
src/proxy/minimal-dap.ts:36): a buggy or compromised debug adapter can OOM the proxy worker.
- IDE-facing side (
src/proxy/dap-mirror-server.ts:186): expose_session mirror clients are loopback + token-gated, but a malformed client (or anything that reaches the loopback port and passes auth) gets the same unbounded buffer. Defense-in-depth says the decoder itself should cap.
Secondary inefficiency: push() does Buffer.concat([this.rawData, data]) on every chunk (:49) — accumulating an N-byte frame from small chunks is O(N²) copying. Fine for typical DAP messages, pathological for large ones (huge variable payloads, base64 blobs some adapters emit).
Proposal
- Add a
maxContentLength option (generous default — e.g. 64 MB, matching the repo's existing maxBuffer: 64MB precedent in docker test utils; env-overridable if someone hits it legitimately). On violation: invoke onError with a distinct context and reset, same recovery contract as the malformed-header path.
- Replace the per-chunk concat with a chunk list + byte count, concatenating once per completed frame (or when scanning for the header separator).
- Property tests in this area already exist (the file header references them) — extend them with a cap-violation case and a many-small-chunks large-frame case.
Problem
DapFrameDecoder(src/proxy/dap-framing.ts:39-110) accepts any finite positiveContent-Lengthwith no upper bound (:96rejects only null/≤0/non-finite). A peer advertising a huge frame makesrawDataaccumulate indefinitely until the "full frame" arrives — i.e. until OOM.Exposure:
src/proxy/minimal-dap.ts:36): a buggy or compromised debug adapter can OOM the proxy worker.src/proxy/dap-mirror-server.ts:186):expose_sessionmirror clients are loopback + token-gated, but a malformed client (or anything that reaches the loopback port and passes auth) gets the same unbounded buffer. Defense-in-depth says the decoder itself should cap.Secondary inefficiency:
push()doesBuffer.concat([this.rawData, data])on every chunk (:49) — accumulating an N-byte frame from small chunks is O(N²) copying. Fine for typical DAP messages, pathological for large ones (huge variable payloads, base64 blobs some adapters emit).Proposal
maxContentLengthoption (generous default — e.g. 64 MB, matching the repo's existingmaxBuffer: 64MBprecedent in docker test utils; env-overridable if someone hits it legitimately). On violation: invokeonErrorwith a distinct context and reset, same recovery contract as the malformed-header path.