T09 · Insecure Skill Coding Practices
Warning
- Location
- api-server/server.js:36
- Finding
- Unbounded HTTP Request Body Enables Remote Memory Exhaustion## Vulnerability Details **File Location**: `api-server/server.js:36-48` **Vulnerability Type**: Unbounded request-body buffering and denial of service **Risk Level**: Medium ### Vulnerable Code ```js async function parseBody(req) { return new Promise((resolve, reject) => { let body = ''; req.on('data', chunk => body += chunk); req.on('end', () => { try { resolve(body ? JSON.parse(body) : {}); } catch (e) { reject(new Error('Invalid JSON')); } }); req.on('error', reject); }); } ``` ### Technical Analysis The HTTP server appends every received chunk to an in-memory string without enforcing a maximum body size, validating `Content-Length`, imposing a request deadline, or stopping slow and incomplete uploads. Each POST request therefore permits attacker-controlled memory consumption. Once the body is received, `JSON.parse` creates an additional in-memory representation, and the supplied text is subsequently processed by multiple regular expressions and statistical-analysis routines. These operations can amplify both memory and CPU consumption. The server can be deployed for external integrations and does not implement authentication or application-level rate limiting. Consequently, any network client able to reach the service can exercise the vulnerable parser. ### Attack Path 1. An operator deploys the HTTP API on a network-accessible interface or behind a public proxy. 2. An attacker connects to `/api/score`, `/api/analyze`, `/api/humanize`, or `/api/stats`. 3. The attacker sends a very large JSON request body or keeps streaming chunks without completing the request. 4. The server continually concatenates the chunks into the `body` string. 5. One large request, or several concurrent requests, exhausts available heap memory and consumes event-loop resources. 6. The Node.js process becomes unresponsive or terminates with an out-of-memory e ...[truncated 403 chars]
- Remediation
- ## Remediation Suggestions - Enforce a conservative byte limit while streaming the request, such as 256 KB or another limit appropriate for expected documents. - Track bytes using `Buffer.byteLength` rather than JavaScript string length. - Reject requests whose declared `Content-Length` exceeds the configured limit. - Stop processing and destroy the request as soon as the streaming limit is exceeded. - Return HTTP `413 Payload Too Large` rather than a generic server error. - Configure header and request timeouts to prevent indefinitely slow uploads. - Apply reverse-proxy limits, concurrency controls, and per-client rate limiting. - Consider processing exceptionally large documents through an authenticated asynchronous job interface. Example hardening pattern: ```js const MAX_BODY_BYTES = 256 * 1024; async function parseBody(req) { return new Promise((resolve, reject) => { const declaredLength = Number(req.headers['content-length'] || 0); if (declaredLength > MAX_BODY_BYTES) { const error = new Error('Request body too large'); error.status = 413; reject(error); req.destroy(); return; } let body = ''; let received = 0; req.on('data', chunk => { received += chunk.length; if (received > MAX_BODY_BYTES) { const error = new Error('Request body too large'); error.status = 413; reject(error); req.destroy(); return; } body += chunk.toString('utf8'); }); req.on('end', () => { try { resolve(body ? JSON.parse(body) : {}); } catch { const error = new Error('Invalid JSON'); error.status = 400; reject(error); } }); req.on('error', reject); }); } ```
