Back to Blog

Node.js July 2026 Security Releases: The Permission Model Is a Seat Belt

Node.js v26.5.1, v24.18.1 and v22.23.2 fix 11 CVEs, three of them in the Permission Model. Why --permission is not a sandbox for agent code, plus an HTTP/2 and mTLS upgrade checklist.

Umut Korkmaz

Published: 4 min read

On Wednesday, July 29, the Node.js project shipped security releases for all three active lines: v26.5.1, v24.18.1 and v22.23.2. The release slipped twice before landing, once for additional testing and validation and once for infrastructure issues, and it closes 11 CVEs: three High, five Medium and three Low. Two threads in the official advisory matter most to me: the HTTP and TLS plumbing every backend leans on, and the fact that three of the eleven fixes are about the Permission Model letting code reach files it was never granted.

What is in the release

The High-severity fixes:

  • CVE-2026-56846: retained HTTP/2 header blocks can evade maxSessionMemory and cause remote memory exhaustion. Affects 24.x and 22.x.
  • CVE-2026-56848: nghttp2_session_mem_send() can be called re-entrantly while nghttp2_session_mem_recv() is running, ending in a heap use-after-free. Affects all three lines.
  • CVE-2026-58043: Permission Model path matching can over-grant filesystem access across radix-tree prefix boundaries, so an attacker granted access to one path can read or write outside the intended allowlist.

The Medium ones are two HTTPS Agent reuse bugs (mTLS client identities reused across requests with different client certificates in CVE-2026-56850, and TLS session reuse skipping hostname verification across identity policies in CVE-2026-58040, an incomplete fix for CVE-2026-48934), a node:sqlite tag store iterator that can re-execute a cached statement after it was reset and rebound (CVE-2026-58041, 26.x and 24.x), dns.resolveAny() aborting the process on responses with more than 256 A records (CVE-2026-58042), and synchronous node:zlib APIs crashing on a spoofed TypedArray length (CVE-2026-58045).

The Low ones: trace events (CVE-2026-56847) and process.report (CVE-2026-58039) writing outside --allow-fs-write paths, and header truncation that can enable request smuggling (CVE-2026-58044): headers beyond maxHeadersCount / maxHeaderPairs can be hidden from req.headers, including Content-Length, while Node still uses them for framing. The release also updates undici and llhttp.

Three holes in the same fence

The advisory does not publish a proof of concept for CVE-2026-58043, so I will not guess at exact path shapes. What the three Permission Model fixes share is more interesting than any single one: an allowlist is only as strong as every code path that consults it. Here it was a path matcher with an edge case at a prefix boundary, plus two diagnostic features, tracing and process reports, that could write files without honoring --allow-fs-write. Diagnostics are exactly the kind of feature nobody thinks of as a write API until someone points it at the wrong directory.

A seat belt, not a sandbox

The Node.js permissions documentation is refreshingly blunt about this. It describes the model as a seat belt that stops trusted code from unintentionally touching resources it was not granted, and says it "does not provide security guarantees in the presence of malicious code." The same page points to the Node.js security policy, under which the runtime trusts any code it is asked to run.

I run several coding agents in parallel every day, and when an agent executes generated scripts or tests, the tempting shortcut is node --permission with a write grant on the workspace, and calling that sandboxed. It is not. If the code could be hostile, whether that is a model following an injected instruction, a compromised dependency or a user-supplied plugin, the boundary has to sit outside the process:

  • a container or VM with no credentials or SSH keys mounted
  • a read-only root filesystem with a single writable workspace
  • a non-root user and restricted network egress
  • --permission inside all of that, as the layer that catches mistakes

This release argues for that layering. It does not prove the fence is now solid.

The Monday checklist for HTTP/2 and mTLS services

  • Confirm the runtime, not the manifest. The engines field says nothing about what is running. Check inside the built image and on CI runners; floating base image tags only help if you rebuild.
node -p "process.versions.node"   # expect 26.5.1, 24.18.1, 22.23.2 or later on that line
  • Know where HTTP/2 terminates. My self-hosted Next.js apps sit behind nginx on a VPS, so my first question is whether Node itself speaks HTTP/2 to the outside world. A service calling http2.createSecureServer() on a public port goes first for the two HTTP/2 Highs.
  • Audit shared HTTPS Agents. If one https.Agent serves requests with different client certificates or different hostname-verification policies, CVE-2026-56850 and CVE-2026-58040 are yours. After patching, I would still give each client identity its own Agent.
  • Check any proxy you wrote in Node. Rebuilding outbound headers from req.headers while piping the body to a reused upstream connection is exactly the CVE-2026-58044 shape.
  • Search for createTagStore if you use node:sqlite on 24.x or 26.x.
  • Treat anything outside 26.x, 24.x and 22.x as exposed. Those are the only lines that got releases, and the advisory notes that End-of-Life versions are always affected.

My take

The patch is routine: bump the version, rebuild, redeploy. The lesson is worth more. Three Permission Model fixes in one release does not mean the feature is bad; it suggests people are stress-testing it, which is healthy. But if your threat model for agent-run or third-party code starts and ends with --permission, write down this week what actually contains that code, and put a real container or VM boundary around it before the next advisory makes the decision for you.

Sources

Primary references used for this post.

  1. nodejs.org/en/blog/vulnerability/july-2026-security-releases (opens in a new tab)
  2. nodejs.org/api/permissions.html (opens in a new tab)

About the author

Umut Korkmaz

Lead Software Engineer

I'm a senior software engineer in Istanbul. Here I write about the tools and releases I've shipped to production myself, and what they taught me along the way.

Picked by shared topics.