T09 · Insecure Skill Coding Practices
- Location
scripts/toutiao.js:65- Finding
Unbounded HTTP Response Buffering and Synchronous Decompression
- Content
View full analysis
{ const chunks = []; res.on('data', (chunk) => chunks.push(chunk)); res.on('end', () => { try { const buffer = Buffer.concat(chunks); const decompressed = decompressBody(buffer, res.headers['content-encoding']); const text = decompressed.toString('utf-8'); const data = JSON.parse(text); resolve(data); } catch (e) { const status = res.statusCode || 0; reject(new Error(`Failed to parse JSON (status=${status}): ${e.message}`)); } }); }); ``` The decompression function invoked by this code uses synchronous decompression: ```js function decompressBody(buffer, contentEncoding) { if (!contentEncoding) return buffer; const encoding = String(contentEncoding).toLowerCase(); if (encoding.includes('gzip')) return zlib.gunzipSync(buffer); if (encoding.includes('deflate')) return zlib.inflateSync(buffer); if (encoding.includes('br')) return zlib.brotliDecompressSync(buffer); return buffer; } ``` ### Technical Analysis The HTTP response is accumulated in an in-memory array without a maximum byte limit. Once the response ends, all chunks are copied into a single buffer and potentially decompressed using synchronous zlib operations. A small compressed response can expand into a substantially larger decompressed payload. Because neither the compressed response nor the decompressed output has a configured size limit, an unexpectedly large response or compression bomb can consume excessive memory. The synchronous decompression methods also block the Node.js event loop until processing completes. The 15-second request timeout does not adequately mitigate this issue. It limits request duration but does not bound the number of bytes a ...[truncated 1714 chars]- Remediation
View remediation
