Node.js Fixes 10 CVEs, 4 in the Permission Model

On July 29, 2026 the Node.js project shipped three security releases at once — 22.23.2, 24.18.1 and 26.5.1 — closing ten CVEs across every supported release line. The count is worth noting, but the distribution matters more: four of the ten sit inside the permission model, the feature many teams now lean on to constrain what a single process can touch.

The problem: we treat the permission model like a sandbox

The permission model landed in Node.js 20 with an appealing premise. Run with --permission, grant only what the workload needs — read from one directory, write to another, no network, no child processes — and the blast radius of a build script or a stray postinstall shrinks to almost nothing. As supply-chain anxiety grew, the flag started showing up in CI configs and container entrypoints as a security control.

Node's own documentation has always been more careful than that. The model is described as a seat belt for trusted code, not a barrier against malicious code, because Node.js trusts any code it is asked to run. "Prevents accidental misuse" and "stops an attacker" are different guarantees, and this release is where the gap became concrete.

What changed

The headline issue is CVE-2026-58043, rated High. A process granted read or write access to a single directory could abuse prefix matching in the radix tree used internally to read or write outside that allowlist. In other words, --allow-fs-read=/srv/app/data did not mean what it looked like it meant — a plain path-traversal class bug against the filesystem whitelist.

Two lower-severity siblings round out the group. CVE-2026-56847 and CVE-2026-58039 let trace events and diagnostic reports write their output to arbitrary locations on disk — the same allowlist escape, arriving through the output path rather than the input path.

Outside the permission model, HTTP/2 is the sharper operational risk. CVE-2026-56848 is a heap use-after-free in nghttp2_session_mem_send(), reachable through re-entrant calls during message processing, with remote code execution as the plausible ceiling. On the 22.x and 24.x lines, CVE-2026-56846 adds header blocks that bypass the configured memory limits and exhaust session memory. The remainder are medium and low findings across https, sqlite, dns, zlib and http, alongside dependency bumps to llhttp 9.4.3 and undici 8.9.0.

A practical example: don't let the flag be the only boundary

Upgrading is non-negotiable, but the architectural lesson outlasts the patch. The general rule: any security guarantee that rests on a single layer is a temporary guarantee. If the data directory is the line that must not be crossed, write that line into application code too — not only into the launch command. Then ask the permission model rather than assuming what it granted.

js
// docs.js
import { readFile } from 'node:fs/promises';
import { resolve } from 'node:path';

const ROOT = '/srv/app/data';

// Layer one: explicit containment check
function safePath(userInput) {
  const target = resolve(ROOT, userInput);
  if (target !== ROOT && !target.startsWith(ROOT + '/')) {
    throw new Error('path escapes data root');
  }
  return target;
}

export async function readDoc(name) {
  const path = safePath(name);

  // Layer two: ask, don't assume
  if (!process.permission.has('fs.read', path)) {
    throw new Error(`fs.read not granted: ${path}`);
  }

  return readFile(path, 'utf8');
}

Then run it with the narrowest grant, and confirm the runtime first:

bash
node --permission --allow-fs-read=/srv/app/data ./server.js

node -p "process.versions.node"
# 22.x → 22.23.2   |   24.x → 24.18.1   |   26.x → 26.5.1

Real-world caveats

  • End-of-life lines are affected too and will not be patched. On 20.x or older, upgrading is the only remediation.
  • The HTTP/2 findings apply to anyone serving http2 directly, and to anyone behind a proxy that carries HTTP/2 all the way to the origin. Check the edge before assuming coverage.
  • process.permission.has() is a useful defensive check, not a substitute for input validation. Both layers, not either one.
  • This is the second large patch wave of the same week, after the Next.js security release. Treating them as one maintenance window is cheaper than two.

Takeaway

Patch now: 22.23.2, 24.18.1 or 26.5.1, depending on your line. Then revisit wherever --permission was quietly promoted from a seat belt into a security boundary. The feature is genuinely useful and will keep improving, but it is documented as a seat belt for a reason — and an architecture built on two independent layers stays standing when one of them gives.

Primary source: Node.js — Wednesday, July 29, 2026 Security Releases