T09 · Insecure Skill Coding Practices
- Location
index.js:5- Finding
Unbounded bc Execution Permits Denial of Service
- Content
View full analysis
Vulnerability Details
File Location:
index.js, lines 5–17
Vulnerability Type: Unrestricted execution of resource-intensive calculator programs
Risk Level: MediumVulnerable Code
js function runBc(expr) { return new Promise((resolve, reject) => { const bc = spawn('bc', ['-l', '-q']); let out = ''; let err = ''; bc.stdout.on('data', chunk => (out += chunk)); bc.stderr.on('data', chunk => (err += chunk)); bc.on('error', reject); bc.on('close', code => { if (code !== 0) reject(new Error(err.trim() || `bc exited with code ${code}`)); else resolve(out.trim()); }); bc.stdin.write(expr + '\n'); bc.stdin.end(); }); }Technical Analysis
User-controlled input is submitted to the full
bclanguage without restrictions. Althoughspawn()uses a fixed executable and argument array and therefore does not directly invoke a command shell,bcitself supports control flow and computationally expensive programs.The wrapper enforces no input-length, execution-time, CPU, memory, or output-size limit. It also accumulates all standard output and standard error in memory. Consequently, a non-terminating program, an expensive arbitrary-precision computation, or a loop that continuously generates output can keep the child process active indefinitely or exhaust host resources.
Attack Path
- An attacker supplies a malicious calculator program through command-line arguments or standard input.
main()accepts the unrestricted input and passes it torunBc().runBc()startsbcand writes the attacker-controlled program to its standard input.- A payload such as
while(1) {}runs indefinitely because no timeout exists. - Alternatively, a computation or output loop consumes excessive CPU or causes the Node.js process to retain unbounded output in memory.
- The affected worker remains occupied or terminates because ...[truncated 427 chars]
- Remediation
View remediation
Remediation Suggestions
- Enforce a strict maximum input length before starting
bc. - Apply an execution deadline and terminate overdue child processes, escalating to
SIGKILLif graceful termination fails. - Cap captured standard output and standard error; terminate the child when either limit is exceeded.
- If the intended feature only requires arithmetic expressions, parse or allowlist supported expression syntax and reject loops, function definitions, and other programmable constructs.
- Run the calculator under operating-system CPU, memory, process, and file-descriptor limits where available.
- Return a controlled error when any input, runtime, or output limit is reached.
- Add tests covering infinite loops, very large computations, oversized inputs, and unbounded-output programs.
- Enforce a strict maximum input length before starting
