Web performance

Node.js 26.13.1, 24.22.3, and 22.23.5 Patch 16 CVEs: HTTP/2 Crashes, HTTPS Heap Leaks, and Runtime Hardening

Node.js has shipped security releases 26.13.1, 24.22.3, and 22.23.5, patching 16 CVEs—including 7 High-severity flaws in HTTP/2, HTTPS, and TLS that can crash servers, leak heap memory, or bypass mTLS. Here is the technical breakdown of the parser re-entrancy mechanics, audit commands, and edge proxy mitigations.

By 0xScorPionSon

11 min read

Node.js 26.13.1, 24.22.3, and 22.23.5 Patch 16 CVEs: HTTP/2 Crashes, HTTPS Heap Leaks, and Runtime Hardening

Node.js 26.13.1 HTTP/2 and TLS Runtime Hardening Infographic

Executive Summary

On November 11, 2026, the Node.js Project released coordinated security updates across all three supported release lines: Node.js 26.13.1 (LTS), Node.js 24.22.3 (LTS), and Node.js 22.23.5 (LTS). The release addresses 16 vulnerabilities—7 High, 6 Medium, and 3 Low—alongside dependency updates for llhttp (to 9.4.4 across all three lines), sqlite (to 3.54.1 across all three lines), brotli (to 1.2.1 on 24.x and 26.x), and undici (7.30.2 on 24.x and 8.12.4 on 26.x).

For production systems and web performance engineers, the operational impact centers on Node.js's native network stack:

  1. Unauthenticated Remote Process Crashes and FD Leaks: Multiple High-severity HTTP/2 and TLS bugs allow an unauthenticated client to abort the Node.js worker process (CVE-2026-123863, CVE-2026-126051) or permanently leak memory and file descriptors (CVE-2026-123865), driving CLOSE_WAIT socket exhaustion.
  2. HTTPS Re-Entrancy Heap Disclosure (CVE-2026-123864): Under a common streaming/early-flush handler pattern (res.flushHeaders() followed later by res.end(chunk)), a zero-length TLS write re-enters llhttp_execute(), causing the server to copy its own heap memory—potentially including TLS private keys and other tenants' request data—into the request body.
  3. Zero Official Workarounds: The official Node.js advisory lists no configuration workaround for any of the 16 CVEs. Upgrading the runtime is the only complete remediation, while End-of-Life (EOL) branches (20.x, 18.x, 25.x) receive no patches.

Release Matrix and Lifecycle Status

All three patched versions are cumulative minor/patch releases within their respective LTS lines, requiring no breaking application code changes.

Node.js Line Release Tag Support Status Included Dependency Bumps
26.x (Lithium) 26.13.1 Active LTS (until Apr 30, 2029) llhttp 9.4.4, undici 8.12.4, sqlite 3.54.1, brotli 1.2.1
24.x (Krypton) 24.22.3 Maintenance LTS (until Apr 30, 2028) llhttp 9.4.4, undici 7.30.2, sqlite 3.54.1, brotli 1.2.1
22.x (Jod) 22.23.5 Maintenance LTS (until Apr 30, 2027) llhttp 9.4.4, sqlite 3.54.1 (no undici or brotli bump)
20.x / 25.x / 18.x Unpatched End-of-Life No fixes issued; EOL versions are always affected

Note on documentation reconciliation: Muhammad Tayyab's release analysis and Phoenix Security highlight two minor discrepancies between the umbrella advisory and per-release changelogs:

  • CVE-2026-126051 (deferred TLS handshake callback crash) affects 24.x and 26.x and is omitted from the 22.23.5 release notes.
  • The umbrella advisory lists CVE-2026-106071 as a Low Permission Model wildcard issue, whereas the individual release notes label the corresponding commit (src: fix the fs permission tree node on wildcard nodes) as CVE-2026-123873.

Technical Mechanics and Runtime Architecture

The seven High-severity vulnerabilities cluster into three runtime subsystems: HTTPS/llhttp parser re-entrancy, HTTP/2 session and stream lifecycle management, and TLS/mTLS state isolation.

+-----------------------------------------------------------------------------+
|            NODE.JS RUNTIME EXPOSURE: DIRECT TERMINATION VS PROXY            |
+-----------------------------------------------------------------------------+
|                                                                             |
|  [ PATTERN A: DIRECT NODE.JS TERMINATION (HIGH EXPOSURE) ]                  |
|   Untrusted Client ---(TLS + HTTP/2)---> Node.js (https / http2 / tls)      |
|     |-- Zero-len TLS write ---> llhttp_execute() re-entry (CVE-2026-123864) |
|     |-- Early reply + abort --> ~Http2Session() assert (CVE-2026-123863)    |
|     |-- RST_STREAM on write --> Http2Stream UAF (CVE-2026-123866 / 123874)  |
|     +-- TLS 1.2 renegotiate --> SNI mTLS bypass (CVE-2026-123872)           |
|                                                                             |
|  [ PATTERN B: EDGE PROXY TERMINATION (REDUCED SURFACE) ]                    |
|   Untrusted Client ---(TLS + HTTP/2)---> [ Nginx / Envoy / ALB ]            |
|                                                  |                          |
|                                    (Cleartext HTTP/1.1 Keep-Alive)          |
|                                                  v                          |
|                                          Node.js (node:http)                |
|     * Mitigates TLS & HTTP/2 parser paths while patch rolls out             |
|     * Does NOT patch outbound https.Agent (CVE-2026-123877) or proxies      |
+-----------------------------------------------------------------------------+

1. HTTPS Parser Re-Entrancy Heap Leak (CVE-2026-123864)

As documented in the Node.js advisory and Phoenix Security's technical breakdown, CVE-2026-123864 (OpenJS CNA CVSS 3.0 score 8.1 / 8.2 alongside CVE-2026-123863) occurs when a Node.js HTTPS server processes a zero-length TLS write that triggers a re-entrant call into llhttp_execute().

Two application conditions are required for exposure:

  • The route handler calls res.flushHeaders() before the request body completes and subsequently finishes the response with res.end() containing a non-empty chunk—a common pattern in Server-Sent Events (SSE), long-polling, and streaming APIs.
  • The route echoes or persists the request body.

Because the parser re-enters over a stale buffer span, the server copies arbitrary process heap memory into the incoming request body. Cleartext node:http servers are not affected by CVE-2026-123864, making this strictly an in-process TLS termination flaw. The fix prevents nested parser execution from empty writes.

2. HTTP/2 Teardown Crashes, FD Exhaustion, and Use-After-Free

Six HTTP/2 CVEs affect node:http2 listeners, impacting both availability (worker aborts and resource exhaustion) and memory safety:

  • CVE-2026-123863 (High, 24.x, 26.x): When a default HTTP/2 server handler sends a response before the client's request body finishes arriving and the client aborts, ~Http2Session() hits a fatal CHECK_EQ(current_nghttp2_memory_, 0) assertion, immediately crashing the Node.js process and dropping all concurrent connections on that worker.
  • CVE-2026-123865 (High, 22.x, 24.x, 26.x): If a protocol error occurs during HTTP/2 connection shutdown (such as a client sending GOAWAY(NO_ERROR)), the session fails to clean up abandoned nghttp2 streams. Memory and file descriptors leak permanently, manifesting as a monotonic climb in CLOSE_WAIT sockets.
  • CVE-2026-123866 (High, 22.x backport / 24.x, 26.x): Stream teardown during a backpressured write can transmit freed heap memory—potentially from other connections' responses—to the peer.
  • CVE-2026-123874 (High, 24.x, 26.x) & CVE-2026-123875 (Medium, 22.x, 24.x, 26.x): Resetting or cancelling a stream created via stream.respondWithFile() or stream.respondWithFD() while a write is pending triggers a use-after-free (CVE-2026-123874) or a NULL pointer dereference in StreamPipe (CVE-2026-123875). Notably, CVE-2026-123874 works over both TLS and cleartext.
  • CVE-2026-123828 & CVE-2026-123868 (Medium): CVE-2026-123828 is a one-byte heap-buffer-overflow in session.altsvc() with a long :authority origin (24.x, 26.x). CVE-2026-123868 allows inbound data queued on an undrained stream to bypass maxSessionMemory accounting (approximately 10 wire bytes per one-byte data frame versus ~114 bytes retained in memory).

3. TLS/mTLS Bypasses and https.Agent Session-Cache Collision

Four TLS vulnerabilities weaken mutual TLS (mTLS) and outbound certificate validation:

  • CVE-2026-123872 (High, 22.x, 24.x, 26.x): During TLS 1.2 renegotiation, a client authenticated for one hostname can unilaterally alter the Server Name Indication (servername) and carry its existing authentication into a virtual host with stricter client-certificate requirements.
  • CVE-2026-126051 (High, 24.x, 26.x): Servers using SNICallback, OCSPRequest, newSession, resumeSession, or server.addContext() can suffer an uncaught exception (crashing the process) if a client sends a crafted ClientHello followed by FIN before deferred handshake callbacks execute.
  • CVE-2026-123867 (Medium, 22.x, 24.x, 26.x): SNI contexts configured with only a CA (server.addContext(host, { ca })) without a certificate fail open to the default CA, bypassing per-host mTLS isolation.
  • CVE-2026-123877 (Medium, 22.x, 24.x, 26.x): Outbound https.Agent instances compute identical TLS session-cache keys when ca is omitted versus when ca: [] is passed, allowing a resumed TLS 1.3 session under the default trust store to satisfy a stricter request.

4. Proxy Credentials, Permission Model, and zlib

Rounding out the 16 fixes:

  • CVE-2026-123871 (Medium, 22.x, 24.x, 26.x): Four error paths in ERR_PROXY_INVALID_CONFIG print embedded proxy username/password credentials verbatim in error messages.
  • CVE-2026-106071 / CVE-2026-123873 & CVE-2026-123829 (Low): Permission Model fixes prevent wildcard over-grants near the permission tree root (--allow-fs-read=/etc/passwd.* granting /etc/passwd) and stop recursive fs.watch() from leaking denied descendant filenames on macOS and Windows.
  • CVE-2026-123862 (Low): Calling deflate.params() followed by destroy() during active streaming can throw an uncatchable ERR_INTERNAL_ASSERTION.

Evidence: Performance Stability and Exploitation Status

As reported by The Hacker News and Phoenix Security, no active exploitation in the wild or public proof-of-concept exploits were reported in the November 11 advisory. However, upstream regression tests for the memory-leak and crash fixes are now public, meaning technical reproduction details are accessible to adversaries.

Five of the 16 CVEs—including CVE-2026-123863 and CVE-2026-123864—were reported by security researcher Chris Rohlf in collaboration with Claude and Anthropic Research.

From a runtime performance and reliability standpoint, unpatched HTTP/2 servers face two severe failure modes:

  • Worker-Pool Starvation: A single unauthenticated request triggering CVE-2026-123863 or CVE-2026-126051 aborts the entire V8/libuv process, forcing PM2/Kubernetes restarts and dropping all in-flight keep-alive connections.
  • Unbounded Memory & Socket Growth: Under CVE-2026-123865 and CVE-2026-123868, abandoned or undrained HTTP/2 streams bypass maxSessionMemory limits (~114 bytes retained per 1-byte frame) and leak file descriptors until the OS hits ulimit -n (EMFILE).

Hardening Playbook: Upgrade, Audit, and Defensive Code

Execute the following steps across all Node.js services, container images, and CI/CD runners. Remember that npm audit inspects node_modules only and will not flag vulnerabilities in the Node.js runtime itself.

Step 1: Inventory Running Runtimes and Pin Patched Images

Verify the exact binary version serving production traffic (not just local developer environments or floating Docker tags):

    # Check active runtime version
node -v
    # Expected patched outputs: v26.13.1, v24.22.3, or v22.23.5

    # Inspect running container images for unpinned or floating tags
docker ps --format "{{.ID}} {{.Image}}" | xargs -I {} sh -c 'echo "{} -> $(docker exec $(echo {} | cut -d" " -f1) node -v 2>/dev/null)"'

Update Dockerfile base images to pin the exact patch release:

    # Pin exact patched runtime rather than floating major tags
FROM node:26.13.1-alpine
    # Or for 24.x / 22.x LTS:
    # FROM node:24.22.3-alpine
    # FROM node:22.23.5-alpine

Step 2: Audit Codebase for Exposed APIs

Search application repositories for the specific APIs that gate exposure to the HTTP/2, HTTPS, and TLS flaws:

    # 1. Check for native HTTP/2 file serving (CVE-2026-123874 / 123875) and TLS listeners
grep -rnE "respondWithFile|respondWithFD|createSecureServer|https\.createServer|tls\.createServer" src/

    # 2. Check for early header flushing (CVE-2026-123864 precondition)
grep -rn "flushHeaders" src/

    # 3. Check for per-host SNI CA overrides (CVE-2026-123867) or empty ca arrays (CVE-2026-123877)
grep -rnE "addContext\(|ca:\s*\[\s*\]" src/

    # 4. Check proxy environment variables for embedded credentials (CVE-2026-123871)
env | grep -iE '^(http|https|all)_proxy=' | grep '@'

Step 3: Isolate https.Agent Trust Policies

Even after upgrading to 26.13.1, 24.22.3, or 22.23.5, never share a single https.Agent across requests with different CA trust requirements:

const https = require("https");

// Safe pattern: isolate each CA trust policy into its own keepAlive Agent
const publicApiAgent = new https.Agent({
  keepAlive: true,
  maxSockets: 64,
});

const internalPinnedAgent = new https.Agent({
  keepAlive: true,
  maxSockets: 32,
  ca: [process.env.INTERNAL_ROOT_CA_PEM],
  minVersion: "TLSv1.3",
});

// Never pass `ca: []` expecting to disable trust; use distinct Agent instances

Step 4: Interim Edge Proxy Offloading (If Upgrade Is Delayed)

While no official workaround exists, teams that cannot immediately restart production fleets can reduce exposure to the TLS and HTTP/2 parser flaws by terminating TLS and HTTP/2 at Nginx or Envoy and proxying cleartext HTTP/1.1 to Node.js:

// Interim edge proxy config: terminates HTTP/2 & TLS outside Node.js
server {
    listen 443 ssl http2;
    server_name api.example.com;

    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_certificate /etc/ssl/certs/api_example_com.crt;
    ssl_certificate_key /etc/ssl/private/api_example_com.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Step 5: Monitor for CLOSE_WAIT Socket Exhaustion and Rotate Exposed Secrets

Before and after upgrading, monitor open file descriptors and CLOSE_WAIT states on Node.js workers:

    # Count CLOSE_WAIT sockets on Node.js processes (symptom of CVE-2026-123865)
ss -tanp | grep node | grep CLOSE-WAIT | wc -l

If an internet-facing HTTPS server matched the CVE-2026-123864 handler pattern (res.flushHeaders() + body echo/storage) prior to patching, evaluate rotating TLS private keys and in-process session secrets—patching stops future leaks but cannot undo prior memory disclosure. Similarly, if ERR_PROXY_INVALID_CONFIG logged proxy credentials (CVE-2026-123871), rotate those proxy passwords and scrub affected log archives.

Step 6: Rollback Notes

Because 26.13.1, 24.22.3, and 22.23.5 are drop-in security patch releases with no breaking API changes, rolling back in an emergency requires only redeploying the prior container digest or switching the version manager (nvm use / fnm use) and restarting the service. Under pm2 + nvm, update the runtime, reinstall pm2, back up dump.pm2, roll apps sequentially with health checks, and restart the pm2 systemd unit cleanly rather than running pm2 update.


Frequently Asked Questions

1. Which Node.js versions fix the 16 November 2026 CVEs?

The fixes ship in Node.js 26.13.1 (LTS), Node.js 24.22.3 (LTS), and Node.js 22.23.5 (LTS), all released on November 11, 2026. Node.js 27 exists only in alpha and is excluded from this release.

2. Is Node.js 20 or Node.js 18 patched?

No. Node.js 20 (Iron) reached End-of-Life on April 30, 2026, and Node.js 25 reached EOL on June 1, 2026. As the official advisory states, "End-of-Life versions are always affected when a security release occurs." Organizations on Node.js 18, 20, or 25 must upgrade to Node.js 22, 24, or 26.

3. Does npm audit detect these 16 vulnerabilities?

No. npm audit scans JavaScript dependencies inside node_modules and package-lock.json. All 16 fixes reside in the Node.js C++/JS runtime and its bundled native dependencies (llhttp, undici, sqlite, brotli), so you must check node -v and container image tags directly.

4. Am I safe from CVE-2026-123864 if Nginx or a cloud load balancer terminates TLS?

Yes, for CVE-2026-123864 specifically. The Node.js advisory confirms that cleartext node:http is not affected by the HTTPS re-entrancy heap leak. However, if your Node.js process speaks HTTP/2 directly (node:http2), it remains exposed to CVE-2026-123874 over cleartext, and outbound https.Agent connections remain exposed to CVE-2026-123877 until upgraded.

5. Why do scanners report CVE-2026-123873 or CVE-2026-126051 inconsistently across Node 22?

The umbrella advisory lists CVE-2026-106071 for the Permission Model wildcard fix, while the individual release notes cite CVE-2026-123873 for the same commit. Additionally, CVE-2026-126051 (deferred TLS handshake callback crash) affects 24.x and 26.x and is not listed in 22.23.5.


Sources

More on Web performance

Web performance

Inside CDN Migration Performance: Why Fast Edge Responses Trigger Origin Overload and How to Warm Caches Without Blocking Crawlers

On November 11, 2026, Google Search Central warned that moving a website to a CDN can trigger an immediate crawl surge on the origin server because faster edge responses raise crawl capacity limits while cold caches pass every first-time URL miss straight back to origin. Turning on blanket CAPTCHA or 403 blocks then drops pages from Search. Here is the technical architecture, cache-warming script, and 429/503 backpressure playbook.

12 min read

Web performance

Inside .NET 11 Runtime Performance: How Runtime Async, JIT Devirtualization, and SIMD Intrinsics Eliminate State Machine Overhead

On November 10, 2026, Microsoft launched .NET 11 featuring CoreCLR Runtime Async, which eliminates legacy Roslyn state-machine structs and cuts deep async call stacks from 13 frames to 5. Paired with elevated x86-64-v2 hardware baselines, JIT devirtualization, and >1024 CPU core scaling, this release redefines managed runtime efficiency. Here is the technical breakdown, architectural analysis, benchmarks, and migration guide.

12 min read

Web performance

Inside streamAppendHTML in Chrome 157: Ending 10 Years of innerHTML Hacks, Streamlining LLM UIs, and Slashing INP

In December 2016, WHATWG issue #2142 asked for a native way to stream content into an HTML element. On November 5, 2026, that decade-long quest concluded with Chrome 157 shipping native HTML streaming setters—led by Element.prototype.streamAppendHTML() and Response.prototype.textStream(). By piping incoming network chunks directly into the browser's C++ HTML parser via a WritableStream, web applications can now render real-time LLM tokens and server-sent partials without main-thread re-parsing overhead, blown INP budgets, or lost input focus. This deep systems analysis explores the DOM streaming architecture, tokenization buffering mechanics, Sanitizer API security, and production Core Web Vitals telemetry.

12 min read

Tell us what is not working

A thirty-minute call, no deck and no obligation. You will leave with a straight answer about whether this is worth building - including if that answer is no.

Start a project

Direct line

hello@codebumble.net
Dhaka, Bangladesh  :   local timeCalls in English or Bangla