T09 · Insecure Skill Coding Practices
- Location
zwds-cli/src/index.js:4- Finding
Unbounded Standard Input Can Cause Memory Exhaustion
- Content
View full analysis
Vulnerability Details
File Location:
zwds-cli/src/index.js, lines 4–7
Vulnerability Type: Uncontrolled resource consumption through unbounded input buffering
Risk Level: MediumVulnerable Code
javascript async function readStdin() { const chunks = []; for await (const c of process.stdin) chunks.push(c); return Buffer.concat(chunks).toString("utf8"); }Technical Analysis
The CLI reads the entire standard-input stream into an array without enforcing a maximum payload size. After retaining every input chunk, it calls
Buffer.concat()and converts the resulting buffer to a UTF-8 string, creating additional memory allocations before JSON parsing or field validation occurs.An attacker or untrusted caller who can invoke the CLI can supply an arbitrarily large stream. Memory consumption therefore grows with the input size and may exceed the Node.js heap or available system memory.
Attack Path
- The attacker invokes
node src/index.jsdirectly or through an application that exposes the CLI. - The attacker streams an extremely large payload to standard input.
readStdin()retains every chunk in memory without a byte limit.Buffer.concat()allocates a combined buffer, andtoString("utf8")creates another representation.- The process becomes unresponsive or terminates because of memory exhaustion before JSON validation is reached.
Impact Assessment
Successful exploitation can terminate or stall the chart-generation process. If the CLI runs inside a shared Agent, worker, or service process without strict resource isolation, the impact may extend to other requests handled by that process or host.
The vulnerability does not provide code execution, additional privileges, filesystem access, or data disclosure. Its confirmed scope is local denial of service against the invoking process and potentially its hosting service.
- The attacker invokes
- Remediation
View remediation
Remediation Suggestions
Enforce a small, documented maximum input size before retaining additional chunks. Stop reading and reject the request immediately when the limit is exceeded.
For example:
javascript async function readStdin(maxBytes = 64 * 1024) { const chunks = []; let totalBytes = 0; for await (const chunk of process.stdin) { totalBytes += chunk.length; if (totalBytes > maxBytes) { throw new Error(`stdin payload exceeds ${maxBytes} bytes`); } chunks.push(chunk); } return Buffer.concat(chunks, totalBytes).toString("utf8"); }Additional hardening should include:
- Apply request-size limits in any wrapper or service that launches the CLI.
- Run the process with memory and execution-time limits.
- Keep error responses generic and machine-readable.
- Add a regression test that submits input above the configured limit and verifies prompt rejection.
