Node.js June 2026 Security Release: 12 CVEs Across v22.23.0, v24.17.0, and v26.3.1, with Two High-Severity TLS and Crypto Fixes

Node.js June 2026 Security Release: 12 CVEs Across v22.23.0, v24.17.0, and v26.3.1, with Two High-Severity TLS and Crypto Fixes

lschvn

The Node.js project shipped a coordinated security release on June 18, 2026, covering every active release line at once: v22.23.0 for the "Jod" LTS, v24.17.0 for the "Krypton" LTS, and v26.3.1 for the Current line. Twelve CVEs land in the drop, two rated High and the rest split between Medium and Low. The release is a security release on every line, with v26.3.1 also receiving the small set of feature patches that follow v26.3.0 (the Buffer pool 64 KiB default, the new httpValidation option, and the permission.drop API) but were not yet covered by the prior security embargo.

The previous Node.js security drop of this shape landed in March 2026 (see our coverage). The pattern is the same: embargoed fixes accumulate, the embargo lifts, and the project ships the entire set on the same day across all three lines. What is different this time is the cluster of TLS and crypto CVEs, which dominate the High and Medium bands. Four of the six Medium entries are TLS-shaped, and one of the two Highs is a WebCrypto output-length guard that affects the crypto.subtle API that a lot of serverless and edge code now depends on.

The two High-severity fixes

CVE-2026-48618, TLS hostname normalization for server identity checks. Matteo Collina's patch targets the path where a Node.js TLS server checks the hostname a client supplied against the certificate it presented. Before the fix, the comparison path was not consistently normalizing the hostnames it was comparing, which let a carefully crafted host (typically one with mixed casing, trailing dots, IDN encoding, or a mix of URL-encoded and raw characters) slip past the check and bind a connection to a virtual host the client did not intend to reach. The patch normalizes the hostname the same way on the SNI side, the certificate-SAN side, and the URL the client originally requested, which aligns Node with OpenSSL 3.x's X509_VERIFY_PARAM_set1_host and the WHATWG URL parser. For anyone running TLS termination inside a Node process rather than at a load balancer, this is the headline fix of the release.

CVE-2026-48933, WebCrypto cipher output length guard. Filip Skokan's fix lands in the SubtleCrypto.encrypt and SubtleCrypto.decrypt paths. Certain algorithms (notably AES-CTR and AES-CBC when the caller asks for a counter- or tag-trimmed output) accept a length parameter that the previous code path did not always enforce against the actual buffer produced by the underlying OpenSSL call. A malicious or buggy caller could pass a length larger than the cipher's output and either read past the intended buffer or, depending on the algorithm, observe bytes that should have been truncated. The patch clamps the returned output to the requested length and validates the input length on encrypt, closing both the read-past-end and the write-past-end cases. This is the kind of fix that matters for code using Node's crypto.subtle for HMAC-based authentication, for passkey flows, and for any library that does envelope encryption in the browser-shaped SubtleCrypto API.

The six Medium fixes

The Medium band is the meat of the release. Six CVEs, all of which can be turned into either a denial-of-service or a low-effort information disclosure, and all of which are worth patching on the normal schedule rather than waiting for a "High only" triage.

  • CVE-2026-48615, proxy credentials in tunnel errors. When a Node.js HTTP client uses the CONNECT method to open a tunnel through an HTTPS proxy, the error path was previously emitting the proxy URL (including the embedded credentials) into the thrown error message. The patch redacts the credential portion before the error is surfaced, so a stack trace or a log file no longer leaks the proxy password. The fix is in lib and test, which means it touches both the runtime path and the test fixtures that check the error shape.
  • CVE-2026-48619, http2 originSet memory growth. The HTTP/2 server path was accepting origin entries into an internal originSet without a hard cap, which let a single connection grow the set unboundedly. The patch sets a reasonable ceiling, after which new entries are rejected. With HTTP/2 in particular, a single TCP connection can serve many requests, so an unbounded per-connection data structure is effectively unbounded per-attacker.
  • CVE-2026-48928, TLS case-sensitive SNI context matching. The SNI-based context selection (servername event, SNICallback) was previously doing a case-sensitive comparison. RFC 6066 mandates case-insensitive SNI matching for the wire format, but Node's internal context selection was stricter than the wire format required, which produced a class of "the same hostname routes to different certificates depending on case" bugs. The fix lowers the comparison to case-insensitive, which is consistent with the wire format and with what OpenSSL itself does.
  • CVE-2026-48930, NUL bytes in DNS hostnames. A hostname that contains an embedded NUL byte (\x00) was previously accepted by the dns and net modules, which is a long-known injection vector because the C-level getaddrinfo and friends treat the NUL as a string terminator. The patch rejects such hostnames at the boundary, which closes the classic "split-the-string-on-NUL" attack pattern that has shown up in every language's networking layer at some point.
  • CVE-2026-48934, TLS session reuse bound to host. The TLS session cache was previously allowing a session resumed from a previous connection to a host to be reused for a different host. The fix binds the session ticket to the hostname the original connection authenticated against, so a client cannot move a session across hosts (which would be a session-fixation vector in any code that relies on session resumption for authentication context).
  • CVE-2026-48937, nghttp2 1.69.0 integration. This is the dependency follow-up. The v22 and v24 lines jump nghttp2 to 1.69.0, which is tagged SEMVER-MAJOR in the Node commit message because upstream shipped breaking integration changes. Tim Perry's follow-up absorbs those into the Node wrapper. The v26 line keeps its 26.2.0 baseline nghttp2 for now.

The four Low fixes

The Low band is permission-model hardening, with one HTTP exception.

  • CVE-2026-48617, process.chdir on writereport. A path where process.chdir was not being checked against the permission model's read/write allow list.
  • CVE-2026-48931, http response queue poisoning in http.Agent. A low-severity class where the agent's response queue could be poisoned by a malicious server, leading to a use-after-free in a narrow race window. Matteo Collina's fix tightens the queue lifecycle.
  • CVE-2026-48935, FileHandle.utimes with permission model. FileHandle.utimes is now disabled when the permission model is active, because the underlying utimes syscall was not on the allow list and could be used as a side channel to learn about the filesystem.
  • CVE-2026-48936, pipe open and chmod net scope (v26 only). The v26 line gets an additional permission tightening around pipe(2) and chmod(2), which are the two syscalls the permission model had left in a half-restricted state.

Dependency updates and the LTS / Current split

Three dependency updates land on every line, and one is LTS-only.

  • OpenSSL 3.5.7 on v22, v24, and v26. This is a routine security refresh; the OpenSSL 3.5.x line is the one Node has been on since v24 went LTS.
  • llhttp 9.4.2 on every line. The HTTP parser refresh is a minor version, no public API change.
  • undici moves to 8.5.0 on v26, 7.28.0 on v24, and 6.27.0 on v22. The version split reflects the Node policy of pinning a different major of undici per release line so that the bundled fetch client tracks the major the line was originally released against.
  • nghttp2 1.69.0 on v22 and v24 only. The v26 line keeps its 26.2.0 baseline.

What to do

If you are on v22 LTS, upgrade to v22.23.0. If you are on v24 LTS, upgrade to v24.17.0. If you are on v26 Current, upgrade to v26.3.1. The release is a security release on every line, so the upgrade is the right move on the normal patch schedule and not one to defer. If you are still on v20, you are out of active LTS and should be planning the move to v22 (or, if your toolchain supports it, v24).

For the TLS and WebCrypto Highs, the practical impact is on code that terminates TLS in the Node process (rather than at a load balancer) and on code that uses crypto.subtle directly (rather than going through a higher-level library like jose). The library wrappers typically sanitize the length argument before calling the underlying API, so the WebCrypto fix is most relevant to code that talks to SubtleCrypto directly. The TLS hostname fix is relevant to every server that uses the servername event or SNICallback to pick a certificate by hostname.

This is the second Node.js security drop of 2026, and the pattern is now familiar: embargoed fixes accumulate across the active lines, the project ships the whole set on a single day, and the LTS and Current releases move together. The TLS-heavy shape of this drop is a reminder that Node's TLS and crypto surfaces are still the highest-volume CVE category, and that the project's habit of bundling them into a single coordinated release is what keeps the upgrade story simple for the people who run Node in production.

Frequently Asked Questions

Related articles

More coverage with overlapping topics and tags.

Node.js 25.9: The stream/iter API Finally Lands as Experimental
security

Node.js 25.9: The stream/iter API Finally Lands as Experimental

Node.js 25.9 adds an experimental stream/iter module for async iteration over streams, a --max-heap-size CLI flag, AsyncLocalStorage with using scopes, TurboSHAKE crypto, and an upgraded npm 11.12.1. Here's what each change means for your code.
OpenAI Codex 0.141 Adds Noise-Encrypted Remote Executors, Cross-OS `PathUri`, a Plugin Marketplace, and a SQLite WAL-Reset Pin
security

OpenAI Codex 0.141 Adds Noise-Encrypted Remote Executors, Cross-OS `PathUri`, a Plugin Marketplace, and a SQLite WAL-Reset Pin

Codex 0.141.0 (June 18, 2026) makes Noise IK the default transport between orchestrator and exec-server, ships a PathUri / NativePathString layer that round-trips POSIX, Windows-drive, and UNC paths without leaking the URI encoding, opens a `created-by-me-remote` plugin marketplace, raises the MCP tool timeout to 300 seconds, and pins the bundled SQLite to 3.51.3 to keep the WAL-reset corruption fix in place after dependency refreshes.
Swoole's AOT compiler is now TypePHP: PHP-syntax code that compiles to native binaries, beta by October 1
runtimes

Swoole's AOT compiler is now TypePHP: PHP-syntax code that compiles to native binaries, beta by October 1

On June 18, 2026, the Swoole team publicly renamed their ahead-of-time PHP compiler to TypePHP, a separate strongly-typed compiled language with full PHP syntax compatibility, a dual static-compile / ZendVM-runtime engine, native Decimal / BigInt / BigFloat types, four strongly-typed C++-backed containers, uniform function call syntax, and direct C++ ABI calls into C, C++, Rust and Go static libraries. A beta is promised by China's National Day (October 1, 2026), with full source-code release to follow. We unpack the dual-engine design, the C++ ABI integration, the self-hosted compiler, what changes against KPHP, HHVM, PeachPie and FrankenPHP, and the open question Roman Pronskiy raised about where the language stops being PHP.

Comments

Log in Log in to join the conversation.

No comments yet. Be the first to share your thoughts.