Overview
Unrestricted Resource Consumption (URC) in Node.js/Express can crash a server or degrade service by exhausting memory or CPU. In Node.js, a single-threaded event loop means that blocking, resource-intensive operations can block all requests; attackers can exploit endpoints that accept large payloads or perform heavy work to cause outages. This guide explains the impact and typical patterns in Express by focusing on URC risks without tying to any CVEs.
URC vulnerabilities occur when endpoints do not enforce input or rate limits, perform CPU-heavy operations on untrusted input, or buffer large data in memory. For example, a route that reads a huge request body or runs nested loops over input can exhaust memory or CPU, leading to timeouts, crashes, or degraded performance for all users.
To detect and remediate, apply strict body size limits via express.json and express.urlencoded, implement rate limiting per IP, validate inputs, avoid synchronous CPU work on the main thread, and offload heavy tasks to worker threads or separate services. Implement streaming or chunked processing for large uploads.
This guide provides a side-by-side example and a set of steps to mitigate URC in Node.js/Express across common patterns.
Code Fix Example
Node.js (Express) API Security Remediation
/* Vulnerable pattern: unbounded CPU work on input */
const express = require('express');
const app = express();
app.post('/compute', express.json(), (req, res) => {
const input = (req.body && typeof req.body.text === 'string') ? req.body.text : '';
let acc = 0;
for (let i = 0; i < input.length; i++) {
for (let j = 0; j < 2000; j++) {
acc += input.charCodeAt(i) * j;
}
}
res.json({ result: acc });
});
/* Fixed: enforce limits to avoid URC */
app.post('/compute-fixed', express.json({ limit: '100kb' }), (req, res) => {
const input = (req.body && typeof req.body.text === 'string') ? req.body.text : '';
const maxLen = 1000;
if (input.length > maxLen) {
return res.status(413).send('Payload too large');
}
let acc = 0;
for (let i = 0; i < input.length; i++) {
for (let j = 0; j < 2000; j++) {
acc += input.charCodeAt(i) * j;
}
}
res.json({ result: acc });
});
app.listen(3000, () => console.log('Server listening on 3000'));