Unrestricted Resource Consumption

Unrestricted Resource Consumption in Node.js (Express) guide [GHSA-p8mm-644p-phmh]

[Updated March 2026] Updated GHSA-p8mm-644p-phmh

Overview

Unrestricted Resource Consumption in Node.js (Express) can permit attackers to exhaust memory or CPU by sending very large request bodies, triggering expensive processing, or flooding the service with concurrent requests. When an Express app buffers the entire payload in memory or performs CPU-intensive work on the main thread without enforcing limits, a single attack payload or rapid request burst can degrade latency, cause memory pressure, or crash the process, potentially affecting other services on the same host. In Node.js/Express, this vulnerability manifests when you rely on in-memory buffering and unbounded parsing. Examples include using body-parsing middleware without size limits, manually collecting request data via req.on('data'), or performing heavy computations inside route handlers on the main event loop. Without payload limits, rate limiting, or controlled concurrency, an attacker can exhaust server resources, causing service degradation or outages in multi-tenant or microservice environments. Remediation combines input limits, streaming, rate controls, and workload offloading. Enforce strict payload size limits in middleware, avoid manual in-memory buffering, and use streaming or streaming-compatible parsers. Apply rate limits, implement timeouts, and move CPU-intensive tasks to worker threads or separate services. Finally, monitor resource usage and alert on anomalies to detect and respond to abuse quickly.

Code Fix Example

Node.js (Express) API Security Remediation
// Vulnerable pattern (in-memory buffering without size limit)
const express = require('express');
const app = express();

app.post('/vuln', (req, res) => {
  let chunks = [];
  req.on('data', (chunk) => chunks.push(chunk));
  req.on('end', () => {
    const body = Buffer.concat(chunks);
    // CPU-intensive operation on main thread
    const result = heavyProcess(body);
    res.json({ ok: true, size: body.length, result });
  });
  req.on('error', () => res.status(400).end());
});

function heavyProcess(b) {
  let s = 0;
  for (let i = 0; i < b.length; i++) s += b[i];
  return s;
}

// Fixed pattern (limits and streaming)
const express2 = require('express');
const app2 = express2();
app2.use(express2.json({ limit: '1mb' }));

app2.post('/fix', (req, res) => {
  const body = req.body; // parsed with limit; prevents unbounded buffering
  const result = safeProcess(body);
  res.json({ ok: true, size: Buffer.byteLength(JSON.stringify(body)), result });
});

function safeProcess(b) {
  let s = 0;
  if (typeof b === 'object') {
    for (const v of Object.values(b)) {
      if (typeof v === 'number') s += v;
    }
  }
  return s;
}

CVE References

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