|
1 | 1 | --- |
2 | | -date: 2026-11-03T23:00:00.000Z |
| 2 | +date: 2026-11-11T00:00:00.000Z |
3 | 3 | category: vulnerability |
4 | 4 | title: Wednesday, November 11, 2026 Security Releases |
5 | 5 | slug: november-2026-security-releases |
6 | 6 | layout: blog-post |
7 | 7 | author: The Node.js Project |
8 | 8 | --- |
9 | 9 |
|
10 | | -# Summary |
| 10 | +# Security releases available |
| 11 | + |
| 12 | +Updates are now available for the 26.x, 24.x, 22.x Node.js release lines for the |
| 13 | +following issues. |
| 14 | + |
| 15 | +## Patched vulnerabilities |
| 16 | + |
| 17 | +This security release includes the following dependency updates to address public vulnerabilities: |
| 18 | + |
| 19 | +- llhttp on 22.x, 24.x, 26.x |
| 20 | +- undici on 24.x, 26.x |
| 21 | +- sqlite on 22.x, 24.x |
| 22 | + |
| 23 | +### HTTP/2: remote abort, `CHECK_EQ(current_nghttp2_memory_, 0)` in `~Http2Session()` (CVE-2026-123863) - (high) |
| 24 | + |
| 25 | +A reachable assertion in Node.js HTTP/2 session teardown lets any unauthenticated |
| 26 | +client abort the server, over both TLS and cleartext. A client can arrange for an |
| 27 | +Http2Stream that still holds nghttp2-allocated header buffers to outlive its |
| 28 | +session: the stream is removed from the session's stream set but never detached, |
| 29 | +so when `~Http2Session()` runs the memory accounting is nonzero and the |
| 30 | +`CHECK_EQ(current_nghttp2_memory_, 0)` assertion fails, terminating the process. |
| 31 | +The trigger needs only a default http2 server whose handler responds before the |
| 32 | +request body has ended, which is typical. It is a variant of CVE-2024-27983 that |
| 33 | +the earlier fix did not cover, because that fix only detached streams still |
| 34 | +tracked in the session. |
| 35 | + |
| 36 | +Impact: |
| 37 | + |
| 38 | +- This vulnerability affects all users in active release lines: 24.x, 26.x |
| 39 | + |
| 40 | +Thank you, to Chris Rohlf in collaboration with Claude and Anthropic Research |
| 41 | +for reporting this vulnerability and thank you mcollina for fixing it. |
| 42 | + |
| 43 | +### HTTPS: a zero-length TLS write re-enters `llhttp_execute()`, and the server copies its own heap into the request body (CVE-2026-123864) - (high) |
| 44 | + |
| 45 | +A re-entrancy flaw in Node.js HTTPS lets an unauthenticated client read memory |
| 46 | +belonging to other connections, including TLS private keys and |
| 47 | +other users' requests. `TLSWrap::DoWrite()` calls `ClearOut()` directly when |
| 48 | +asked to write zero bytes; if that write is issued from JavaScript running inside |
| 49 | +the HTTP parser's `on_body` callback, `ClearOut()` decrypts the next TLS record |
| 50 | +while the parser is still mid-body, re-entering `llhttp_execute()` and causing a |
| 51 | +use-after-free and an out-of-bounds heap read. The server then copies that freed |
| 52 | +or unrelated heap memory into the response for the request body. Triggering it |
| 53 | +requires a handler that calls `res.flushHeaders()` before the request body ends |
| 54 | +and later calls `res.end()` with a non-empty chunk, and reading the leaked memory |
| 55 | +requires any ordinary route that echoes or stores a request body. Cleartext |
| 56 | +`node:http` is not affected. |
| 57 | + |
| 58 | +Impact: |
| 59 | + |
| 60 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 61 | + |
| 62 | +Thank you, to Chris Rohlf in collaboration with Claude and Anthropic Research |
| 63 | +for reporting this vulnerability and thank you mcollina for fixing it. |
| 64 | + |
| 65 | +### HTTP/2 sessions never clean up if a protocol error is triggered during connection shutdown (CVE-2026-123865) - (high) |
| 66 | + |
| 67 | +An unauthenticated HTTP/2 client can permanently leak Node.js server memory and |
| 68 | +file descriptors. If a peer triggers a protocol error, for example an oversized |
| 69 | +frame header, while the session is already shutting down, nghttp2 tears the |
| 70 | +session down internally but Node.js never notices, leaving a dangling session: |
| 71 | +the socket stays in `CLOSE_WAIT` and all of Node.js HTTP/2 state for that |
| 72 | +connection is held in memory indefinitely, with no further cost to the attacker. |
| 73 | +The attacker can start the shutdown remotely by sending `GOAWAY(NO_ERROR)`, so |
| 74 | +it is reliable against default HTTP/2 servers. It is an incomplete-fix case of |
| 75 | +CVE-2026-48937: that fix detected nghttp2 internal terminations by watching for |
| 76 | +`GOAWAY` sent while not shutting down, but missed terminations that arrive while |
| 77 | +the session is already shutting down. |
| 78 | + |
| 79 | +Impact: |
| 80 | + |
| 81 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 82 | + |
| 83 | +Thank you, to pimterry for reporting this vulnerability and thank you mcollina for fixing it. |
| 84 | + |
| 85 | +### HTTP/2 stream teardown can send freed response memory to the peer (CVE-2026-123866) - (high) |
| 86 | + |
| 87 | +A use-after-free in Node.js HTTP/2 stream teardown can leak response memory, |
| 88 | +including the contents of other connections' response buffers, to a peer. When a |
| 89 | +stream is torn down while a write is still backpressured, for example by a peer |
| 90 | +`RST_STREAM` or by the server's own per-stream timeout destroying the stream, the |
| 91 | +stream's response buffer is freed but a reference to it is still used, so freed |
| 92 | +or unrelated heap memory is written to the socket instead of the intended |
| 93 | +response. On Node.js 26.x and 24.x the teardown can be driven purely by a remote |
| 94 | +peer once the window-size change from 26.9.0 and 24.22.0 is present, and on all |
| 95 | +supported lines the same defect is reachable through an application-initiated |
| 96 | +teardown such as a per-stream idle timeout. |
| 97 | + |
| 98 | +Impact: |
| 99 | + |
| 100 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 101 | + |
| 102 | +Thank you, to aidan02 for reporting this vulnerability and thank you mcollina for fixing it. |
| 103 | + |
| 104 | +### Node.js is vulnerable to a remotely triggerable uncaught exception in TLS servers via deferred handshake callbacks (CVE-2026-126051) - (high) |
| 105 | + |
| 106 | +A deferred-callback use-after-destroy in Node.js TLS server handshake handling |
| 107 | +allows a remote, unauthenticated attacker to terminate the server process. When |
| 108 | +a TLS server uses any of the `SNICallback`, `OCSPRequest`, `newSession`, or |
| 109 | +`resumeSession` hooks, or `server.addContext()`, the corresponding OpenSSL |
| 110 | +callbacks are deferred, and the deferred code does not handle the underlying |
| 111 | +socket being destroyed between scheduling and execution. By sending a client |
| 112 | +hello that reaches the vulnerable path (for example, no SNI together with an |
| 113 | +OCSP request) followed by padding and a socket FIN, an attacker makes OpenSSL |
| 114 | +deliver the client hello and the end-of-file in the same tick, so the socket is |
| 115 | +destroyed before the deferred callback runs and the process raises an uncaught |
| 116 | +exception instead of emitting an `'error'` event. |
| 117 | + |
| 118 | +Impact: |
| 119 | + |
| 120 | +- This vulnerability affects all users in active release lines: 24.x, 26.x |
| 121 | + |
| 122 | +Thank you, to pimterry for reporting this vulnerability and for fixing it. |
| 123 | + |
| 124 | +### TLS 1.2 renegotiation allows clients to change servername unilaterally to bypass client certificate authentication (CVE-2026-123872) - (high) |
| 125 | + |
| 126 | +A client certificate authentication bypass in Node.js TLS lets a client change |
| 127 | +the servername during TLS 1.2 renegotiation to reach endpoints it was not |
| 128 | +authorized for. On a server that applies different client-certificate policies |
| 129 | +per hostname, for example stricter admin-only client-cert auth on one host and |
| 130 | +ordinary client-cert auth on another, a client that authenticates for a permitted |
| 131 | +host can renegotiate the TLS 1.2 connection under a different servername and carry |
| 132 | +its existing authentication to the protected host, bypassing the stricter policy. |
| 133 | + |
| 134 | +Impact: |
| 135 | + |
| 136 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 137 | + |
| 138 | +Thank you, to pimterry for reporting this vulnerability and for fixing it. |
| 139 | + |
| 140 | +### HTTP/2: use-after-free of `Http2Stream` when a `respondWithFile()` stream is reset during a pending write (CVE-2026-123874) - (high) |
| 141 | + |
| 142 | +A use-after-free in Node.js HTTP/2 lets an unauthenticated client corrupt server |
| 143 | +memory, over both TLS and cleartext, when the server serves files with |
| 144 | +`respondWithFile()` or `respondWithFD()`. A client can make the server free an |
| 145 | +`Http2Stream` while a write request that points to it is still queued on the |
| 146 | +socket; when that write completes, the code dereferences and makes a virtual call |
| 147 | +through the freed object. The only precondition is that the application serves a |
| 148 | +file with `stream.respondWithFile()` or `stream.respondWithFD()`, with default |
| 149 | +settings otherwise. |
| 150 | + |
| 151 | +Impact: |
| 152 | + |
| 153 | +- This vulnerability affects all users in active release lines: 24.x, 26.x |
| 154 | + |
| 155 | +Thank you, to Chris Rohlf in collaboration with Claude and Anthropic Research |
| 156 | +for reporting this vulnerability and thank you mcollina for fixing it. |
| 157 | + |
| 158 | +### Remote unauthenticated HTTP/2 heap-buffer-overflow in `session.altsvc()` with a long origin (CVE-2026-123828) - (medium) |
| 159 | + |
| 160 | +A one-byte heap buffer overflow in Node.js HTTP/2 Alt-Svc handling lets a remote, |
| 161 | +unauthenticated attacker corrupt process memory. When an application passes an |
| 162 | +attacker-controlled value such as a request's `:authority` header to |
| 163 | +`Http2Session.altsvc()`, the AltSvc implementation in `src/node_http2.cc` |
| 164 | +allocates a buffer sized to the origin length and then writes it with a null |
| 165 | +terminator, placing one byte past the end of the allocation. A single request |
| 166 | +carrying a long but syntactically valid `:authority` triggers the out-of-bounds |
| 167 | +write, which aborts the process and serves as a remote heap-corruption primitive. |
| 168 | + |
| 169 | +Impact: |
| 170 | + |
| 171 | +- This vulnerability affects all users in active release lines: 24.x, 26.x |
| 172 | + |
| 173 | +Thank you, to zonduu for reporting this vulnerability and thank you mcollina for fixing it. |
| 174 | + |
| 175 | +### CA-only SNI client-CA overrides fail open to the default CA, bypassing per-host mTLS authorization (CVE-2026-123867) - (medium) |
| 176 | + |
| 177 | +A per-host mutual-TLS authorization bypass in Node.js lets a client authorized |
| 178 | +for the default hostname reach a protected hostname it is not authorized for. |
| 179 | +When a TLS server assigns a hostname a different client-certificate CA with |
| 180 | +`server.addContext(host, { ca: protectedCA })` but no server certificate in that |
| 181 | +SNI context, the per-host client CA is never installed and the handshake falls |
| 182 | +back to the default client CA. In `src/crypto/crypto_tls.cc`, `CertCbDone` |
| 183 | +installs the SNI context's CA only when `setSniContext` succeeds, but |
| 184 | +`setSniContext` returns `false` for a context with no server certificate, so a |
| 185 | +CA-only SNI context silently keeps the default CA. A client holding a certificate |
| 186 | +trusted by the default CA, but not the protected CA, can therefore complete mTLS |
| 187 | +to the protected hostname and read its response even with `requestCert` and |
| 188 | +`rejectUnauthorized` enabled, while a client certified by the protected CA is |
| 189 | +rejected. |
| 190 | + |
| 191 | +Impact: |
| 192 | + |
| 193 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 194 | + |
| 195 | +Thank you, to aur0r4_glyph for reporting this vulnerability and thank you mcollina for fixing it. |
| 196 | + |
| 197 | +### HTTP/2 inbound data queued on an undrained stream is charged to no session budget, so `maxSessionMemory` neither bounds it nor refuses new streams (CVE-2026-123868) - (medium) |
| 198 | + |
| 199 | +An unauthenticated HTTP/2 client can exhaust Node.js server memory because |
| 200 | +inbound data queued on an undrained stream is charged to no session budget. Each |
| 201 | +inbound data frame creates one JavaScript Buffer view in the receiving stream's |
| 202 | +readable queue, but nothing charges that queue to `current_session_memory_`: the |
| 203 | +socket read buffer is accounted only during parsing and released immediately, so |
| 204 | +whatever stays queued is accounted to nothing. A peer that fills a stream's |
| 205 | +receive window with one-byte data frames pays about 10 wire bytes per frame |
| 206 | +while the server retains about 114 bytes per frame, so a single stream on one |
| 207 | +connection can retain hundreds of megabytes from tens of megabytes sent. |
| 208 | +`maxSessionMemory` neither bounds the growth nor refuses new streams, because |
| 209 | +`Http2Session::CanAddStream` gates admission on the same counter that never sees |
| 210 | +the queue. |
| 211 | + |
| 212 | +Impact: |
| 213 | + |
| 214 | +- This vulnerability affects all users in active release lines: 24.x, 26.x |
| 215 | + |
| 216 | +Thank you, to jiri1234 for reporting this vulnerability and thank you mcollina for fixing it. |
| 217 | + |
| 218 | +### Proxy credentials disclosed in `ERR_PROXY_INVALID_CONFIG` error messages (CVE-2026-123871) - (medium) |
| 219 | + |
| 220 | +Node.js discloses proxy credentials in `ERR_PROXY_INVALID_CONFIG` error messages. |
| 221 | +CVE-2026-48615 established that a proxy credential must not appear in a Node.js |
| 222 | +error message and redacted the username and password from `ProxyConfig.href`, |
| 223 | +but that fix missed four error paths in the same subsystem, one of them inside |
| 224 | +the same constructor, which interpolate the raw proxy URL, credentials included, |
| 225 | +into an `ERR_PROXY_INVALID_CONFIG` message. The proxy URL comes from the |
| 226 | +environment, but the defect is the sink: a secret that Node.js redacts everywhere |
| 227 | +else is emitted verbatim into a much wider audience than the process environment, |
| 228 | +such as `stderr`, container logs, log aggregation, and crash reporting services. |
| 229 | + |
| 230 | +Impact: |
| 231 | + |
| 232 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 233 | + |
| 234 | +Thank you, to p-v-p for reporting this vulnerability and thank you mcollina for fixing it. |
| 235 | + |
| 236 | +### Certificate validation bypass in Node.js `https.Agent` via cross-policy TLS session reuse (CVE-2026-123877) - (medium) |
| 237 | + |
| 238 | +A certificate validation bypass in Node.js `https.Agent` lets a cached TLS session |
| 239 | +authenticated under one CA policy be reused by a later request with a stricter policy. |
| 240 | +`https.Agent.prototype.getName()` assigns the same `Agent` and session-cache key |
| 241 | +to a request that omits ca and one that explicitly supplies `ca: []`, because an |
| 242 | +omitted value appends nothing to the key while an empty array stringifies to an |
| 243 | +empty string. The two policies differ: omitting ca uses the default trust store, |
| 244 | +while supplying ca replaces it. Since they share a key, a TLS session authenticated |
| 245 | +under the broader default policy is handed to a new connection made under the later |
| 246 | +`ca: []` policy, and TLS 1.3 session resumption carries the earlier authentication |
| 247 | +forward, so the second request reports `authorized === true` and transmits |
| 248 | +confidential data to a server its own CA policy would reject on a fresh connection. |
| 249 | + |
| 250 | +Impact: |
| 251 | + |
| 252 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 253 | + |
| 254 | +Thank you, to aegis1337 and mickeyjoe for reporting this vulnerability and |
| 255 | +thank you mcollina for fixing it. |
| 256 | + |
| 257 | +### HTTP/2: cancelling one `respondWithFile()` download crashes the server (NULL dereference in `StreamPipe`) (CVE-2026-123875) - (medium) |
| 258 | + |
| 259 | +A NULL pointer dereference in Node.js HTTP/2 lets an unauthenticated client crash |
| 260 | +the server, over both TLS and cleartext, by cancelling file downloads. When the |
| 261 | +server serves a file with `stream.respondWithFile()` or `stream.respondWithFD()` |
| 262 | +and the client cancels the request, a `StreamPipe` used for the transfer is torn |
| 263 | +down in an order that leaves a `NULL` pointer which is then dereferenced, aborting |
| 264 | +the process. No crafted frames are needed, and a handful of cancelled requests |
| 265 | +against a default file-serving handler is enough. |
| 266 | + |
| 267 | +Impact: |
| 268 | + |
| 269 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 270 | + |
| 271 | +Thank you, to Chris Rohlf in collaboration with Claude and Anthropic Research for |
| 272 | +reporting this vulnerability and thank you mcollina for fixing it. |
| 273 | + |
| 274 | +### Permission Model Bypass in recursive fs.watch Leaks Names of Denied Descendants (CVE-2026-123829) - (low) |
| 275 | + |
| 276 | +A Permission Model bypass in Node.js recursive file watching discloses the names |
| 277 | +of files and directories the process is not permitted to read. On macOS and |
| 278 | +Windows, `fs.watch()` and `fs.promises.watch()` in recursive mode are backed by |
| 279 | +the native libuv watcher: `FSEventWrap::Start` checks `kFileSystemRead` only once, |
| 280 | +on the watched root, and `FSEventWrap::OnEvent` then forwards every filename |
| 281 | +libuv reports (relative paths at any depth) to the JavaScript callback without |
| 282 | +checking that each path is covered by the read grant. Code running under |
| 283 | +`--permission` with an exact read grant on a directory can therefore learn names |
| 284 | +such as sub/secret.txt even though readdir on that subdirectory is denied. The |
| 285 | +flaw exposes names and timing metadata, not file contents, and requires macOS or |
| 286 | +Windows plus files created under the watched directory by another actor. |
| 287 | + |
| 288 | +Impact: |
| 289 | + |
| 290 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 291 | + |
| 292 | +Thank you, to Trail of Bits (OpenAI) for reporting this vulnerability and thank |
| 293 | +you RafaelGSS for fixing it. |
| 294 | + |
| 295 | +### zlib: a pending `params()` plus `destroy()` throws an uncatchable `ERR_INTERNAL_ASSERTION` (CVE-2026-123862) - (low) |
| 296 | + |
| 297 | +An uncatchable exception in the Node.js zlib streaming API lets a peer crash a |
| 298 | +process by disconnecting while data is being compressed. `zlib.params()` queues |
| 299 | +a flush and completes its work in that write's callback; if the stream is |
| 300 | +destroyed first, as `pipeline()` does when the peer goes away, `Writable` still |
| 301 | +invokes the callback with an error, but the callback ignores its arguments and |
| 302 | +asserts that the native handle still exists. The handle is gone, so an |
| 303 | +`ERR_INTERNAL_ASSERTION` is thrown from inside stream internals and bypasses the |
| 304 | +stream's error event, the `params()` callback, and the `pipeline()` callback, |
| 305 | +terminating the process. An application is affected only if it calls |
| 306 | +`deflate.params()` while streaming to a peer, which is uncommon. |
| 307 | + |
| 308 | +Impact: |
| 309 | + |
| 310 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 311 | + |
| 312 | +Thank you, to Chris Rohlf in collaboration with Claude and Anthropic Research |
| 313 | +for reporting this vulnerability and thank you mcollina for fixing it. |
| 314 | + |
| 315 | +### Permission Model filesystem over-grant via wildcard radix lookup (CVE-2026-106071) - (low) |
| 316 | + |
| 317 | +A Node.js Permission Model filesystem over-grant lets a wildcard `--allow-fs-read` |
| 318 | +or `--allow-fs-write` rule match paths it should not. When the requested path is |
| 319 | +shorter than the prefix of a wildcard grant, the radix tree lookup stops comparing |
| 320 | +early and treats the path as a match, so for example `--allow-fs-read=/etc/passwd.*` |
| 321 | +also allows reading `/etc/passwd`. It requires the wildcard grant to sit directly |
| 322 | +under the root of the permission tree, such as when it is the only grant for that scope. |
| 323 | + |
| 324 | +Impact: |
| 325 | + |
| 326 | +- This vulnerability affects all users in active release lines: 22.x, 24.x, 26.x |
| 327 | + |
| 328 | +Thank you, to malikhamzaiqbal for reporting this vulnerability and thank you jasnell for fixing it. |
| 329 | + |
| 330 | +## Downloads and release details |
| 331 | + |
| 332 | +- [Node.js v22.23.5](/blog/release/v22.23.5/) |
| 333 | +- [Node.js v24.22.3](/blog/release/v24.22.3/) |
| 334 | +- [Node.js v26.13.1](/blog/release/v26.13.1/) |
| 335 | + |
| 336 | +--- |
11 | 337 |
|
12 | 338 | The Node.js project will release new versions of the 26.x, 24.x, 22.x |
13 | 339 | releases lines on or shortly after, Wednesday, November 11, 2026 in order to address: |
|
0 commit comments