Unrestricted Resource Consumption

Unrestricted Resource Consumption - Node.js (Express) [GHSA-q5pr-72pq-83v3]

[Updated March 2026] Updated GHSA-q5pr-72pq-83v3

Overview

Unrestricted Resource Consumption can cripple a Node.js Express app by allowing an attacker to exhaust CPU or memory and push the process toward OOM or crash. In production, this can degrade or disable services, trigger cascading failures, and force expensive auto-scaling in containerized environments. Because Node.js runs on a single event loop, CPU-heavy operations can block requests from other clients for extended periods. In Express apps, this vulnerability often shows up when requests trigger unbounded work or large payloads are read fully into memory without limits. Examples include parsing very large JSON bodies, reading files into memory, or performing CPU-intensive loops that scale with input size, effectively letting an attacker drive your service into a denial-of-service state. Remediation involves defense-in-depth: enforce strict input and payload size limits, apply rate limiting, and avoid blocking the event loop with unbounded work. Offload heavy tasks to workers or queues, and process input in chunks or streams to preserve backpressure. Also implement timeouts and monitor resource usage to detect abuse early. No CVEs are provided in this guide. The guidance reflects typical mitigation patterns for Unrestricted Resource Consumption in Node.js/Express and helps prevent denial of service due to unbounded resource usage.

Code Fix Example

Node.js (Express) API Security Remediation
// Vulnerable pattern (no payload limit, heavy work on main thread)
const express = require('express');
const app = express();
// No size limit
app.use(express.json());

app.post('/process', (req, res) => {
  const data = req.body.data;
  // Unbounded CPU-bound work on main thread
  let acc = 0;
  for (let i = 0; i < (data ? data.length * 10000 : 0); i++) {
    acc += i;
  }
  res.json({ result: acc });
});

app.listen(3000, () => console.log('vulnerable server listening'));

// Fixed pattern (limit payload and chunk work to yield back to event loop)
const express2 = require('express');
const app2 = express2();
// Limit payload size to 100 KB
app2.use(express2.json({ limit: '100kb' }));

app2.post('/process', (req, res) => {
  const data = req.body.data;
  if (!data) return res.status(400).send('Missing data');
  // Process in chunks to avoid blocking for long
  let acc = 0;
  let idx = 0;
  const chunk = 50000;
  function step() {
    const end = Math.min(idx + chunk, data.length);
    for (let i = idx; i < end; i++) {
      acc += i % 3;
    }
    idx = end;
    if (idx < data.length) {
      setImmediate(step);
    } else {
      res.json({ result: acc });
    }
  }
  step();
});

app2.listen(3001, () => console.log('fixed server listening'));

CVE References

Choose which optional cookies to allow. You can change this any time.