Node.js 22.23.3 ships as LTS 'Jod' with an HTTP/2 use-after-free fix
Node.js 22.23.3 landed on September 23, 2026, and the headline change is a memory-safety bug fix in the HTTP/2 stack. This point release also adds two Node-API functions for SharedArrayBuffer work and rolls forward npm, OpenSSL, ICU, Undici, and corepack. Antoine du Hamel announced it, Juan José Arboleda prepared the release, and most of it needs no code changes on your end.
Node.js versions split into streams. The Current line runs v26 and moves fastest, but the LTS lines are where organizations put their production systems. A point release like 22.23.3 is on purpose conservative. Instead of shipping brand-new APIs, it aggregates changes already proven in Current and staging branches and backports them. That is why the most consequential item here is not a feature. It is a heap use-after-free correction in HTTP/2 that closes a genuine crash path.
The HTTP/2 fix that actually matters
The single most important change in this release is not under "Notable Changes." It lives buried in the general commit log, so it is worth pulling out into the light. The PR is #64166, titled "http2: avoid uaf while receiving and sending rst_stream," written by contributor Evgeniy Gorbanev and reviewed by Matteo Collina, Tim Perry, and Rafael Gonzaga.
The bug is a use-after-free error in the http2 server. It sits inside nghttp2_session_mem_recv2(), the C function Node embeds to speak HTTP/2. nghttp2 processes incoming bytes through callbacks, and here a race existed between receiving data and tearing down streams.
When a stream closed while nghttp2 was still mid-processing a receive buffer, Node could touch memory nghttp2 had already freed. That is a textbook use-after-free, the kind ASAN flags and the kind that can spiral into a crash or, in the worst case, remote code execution against your HTTP/2 server.
Tim Perry nailed the root cause in a review. Node was effectively calling into nghttp2's send methods while still "receiving," which breaks nghttp2's own documented rule against calling those methods from within callbacks.
The fix adds an is_receiving() flag around the nghttp2_session_mem_recv() call and defers RST_STREAM handling until the receive finishes. A stream never closes while nghttp2 is still working on it.
Here is a bit of context only the tracking history reveals. The fix landed on main in July 2026, then went through a messy backport that touched both v26.x and v24.x. A follow-up assertion failure popped up when a session was destroyed from within a 'stream' handler. The team had to reject new streams during session teardown and destroy stale C++ handles safely before it could merge into v22.x-staging.
If you run an HTTP/2 server on Node 22, this is the change that matters most.
Two new Node-API paths for shared memory
Node-API is the stable ABI interface that lets C/C++ authors build addons that work across Node.js versions without recompiling. Two changes touch it here.
First, napi_create_typedarray() now accepts a SharedArrayBuffer. It used to take only an ArrayBuffer, even though napi_create_dataview() already handled both. The change aligns the C API with JavaScript semantics, where TypedArrays can legitimately sit on shared buffers for cross-thread work.
Second, Ben Noordhuis adds napi_create_external_sharedarraybuffer(). An "external" buffer tells V8 the memory lives outside its normal allocation path, which matters when you share buffers between native code and JavaScript without copying.
Both landed on main in early 2026 before being backported. For addon authors working with worker_threads and shared-memory concurrency, these close gaps that have stuck around for a while. Not a huge leap. It just removes friction where there previously was none.
The dependency roll you should respect
The rest of the release is the maintenance cadence you expect from LTS. npm jumps to 10.9.9, OpenSSL to 3.5.8, and the bundled root cert store moves to NSS 3.125.
Node ships its own build of OpenSSL, so this update keeps crypto correctness and TLS handling current. That particular change was automated and bot-driven, and a follow-up by Filip Skokan handled the varied CCM final-byte behavior across platforms. Since TLS, the crypto module, and certificate handling all rest on OpenSSL, it matters more than the boring presentation suggests.
The other bumps read like a checklist but still count. ICU goes to 78.3 for locale-aware formatting. Undici reaches 6.28.1, keeping the fetch, Request, and Response globals working against current web APIs. corepack bumps to 0.36.0, the per-project package manager shim.
Smaller corrections worth knowing
Several correctness patches rode in from staging, and a couple are quietly useful.
The url module now handles unparsable serialized URLs in setters instead of misbehaving. ESM loader patchability for fs came back after a regression, which matters for tooling that hooks into module loading.
Then there is the Windows task runner hardening, where environment variables are now properly escaped. That closes a shell-injection-style footgun, the kind of thing you only notice once it bites you.
Function names are now preserved in util even without source-map names, giving you cleaner stack traces when debugging.
Head here to the official release announcement.
