Unrestricted Resource Consumption

Unrestricted Resource Consumption in Node.js Express [CVE-2026-39865]

[Updated Jun 2026] Updated CVE-2026-39865

Overview

Unrestricted Resource Consumption vulnerabilities in server-side JavaScript can occur when resource cleanup paths misbehave under high concurrency. CVE-2026-39865 describes a state corruption bug in Axios pre-1.13.2 related to HTTP/2 session cleanup within the Http2Sessions.getSession() path. The flaw arises when concurrent session closures manipulate the internal sessions array, potentially destabilizing the client process and creating denial-of-service conditions due to resource exhaustion or crashes. The CVE maps to CWE-400 (Unrestricted Resource Consumption) and CWE-662 (flawed cleanup of resources leading to instability). In Node.js (Express) apps that rely on Axios for outbound HTTP/2 requests, this class of bug can translate into unstable behavior under load or when interacting with servers that induce rapid session turnover.

Affected Versions

Axios pre-1.13.2 (e.g., versions < 1.13.2) are affected by CVE-2026-39865.

Code Fix Example

Node.js (Express) API Security Remediation
// Vulnerable (simulated pattern) demonstrating concurrent cleanup that mutates the sessions list
class Http2SessionManagerVulnerable {
  constructor() {
    this.sessions = [];
  }
  addSession(session) {
    this.sessions.push(session);
  }
  async closeAll() {
    await Promise.all(this.sessions.map(s => s.close().finally(() => {
      const idx = this.sessions.indexOf(s);
      if (idx !== -1) this.sessions.splice(idx, 1); // risky: mutating while other closures may still reference the array
    })));
  }
}

// Fixed (simulated) pattern that avoids in-place mutation during concurrent cleanup
class Http2SessionManagerFixed {
  constructor() {
    this.sessions = [];
  }
  addSession(session) {
    this.sessions.push(session);
  }
  async closeAll() {
    // Snapshot and clear the list before closing to avoid in-flight mutations
    const toClose = this.sessions.slice();
    this.sessions.length = 0;
    await Promise.all(toClose.map(s => s.close()));
  }
}

// Optional mock session to illustrate behavior
class MockSession {
  constructor(id) { this.id = id; }
  close() { return new Promise(resolve => setTimeout(resolve, 10)); }
}

// Example usage (not executed here):
// const mgrV = new Http2SessionManagerVulnerable();
// const mgrF = new Http2SessionManagerFixed();
// // add and close sessions concurrently to observe differences

CVE References

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