Overview
Unrestricted Resource Consumption in Node.js/Express can cause denial of service by exhausting CPU, memory, or file descriptors. Attackers may send oversized requests, trigger CPU-intensive operations, or flood the app with concurrent connections, potentially crashing the process or making it unresponsive. In absence of CVEs provided for this write-up, treat this as a class of vulnerability with widely known impact: memory pressure leading to OOM, long GC pauses, and degraded latency across all users.
In Node.js, this class often manifests when request bodies are parsed and buffered entirely in memory (e.g., unbounded JSON or URL-encoded payloads) or when CPU-intensive work is performed synchronously inside request handlers. Express apps commonly rely on middleware like body-parser; if limits are not enforced, a single large payload or rapid burst of requests can exhaust heap, event loop time, or worker availability. Large file uploads, unthrottled streaming, or unbounded stream processing can similarly deplete memory and cause backpressure collapse across the system.
Typical real-world patterns include: (1) JSON or URL-encoded parsers with no size limit; (2) file upload handlers buffering entire files in memory; (3) CPU-heavy validation or transformation performed in the request path; (4) lack of rate limiting or concurrency controls that allow floods of requests. Remediation focuses on constraining input size, streaming data rather than buffering, and applying request flood protection, while ensuring timeouts and graceful degradation.
Code Fix Example
Node.js (Express) API Security Remediation
Vulnerable:
const express = require('express');
const appV = express();
appV.use(express.json());
appV.post('/upload', (req, res) => {
const payload = req.body;
res.json({ size: payload ? Object.keys(payload).length : 0 });
});
Fixed:
const express = require('express');
const appF = express();
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100, message: 'Too many requests' });
appF.use(express.json({ limit: '1mb' }));
appF.use(express.urlencoded({ extended: true, limit: '1mb' }));
appF.use(limiter);
appF.post('/upload', (req, res) => {
const payload = req.body;
res.json({ size: payload ? Object.keys(payload).length : 0 });
});
appV.listen(3000, () => console.log('Vulnerable server listening on port 3000'));
appF.listen(3001, () => console.log('Fixed server listening on port 3001'));