Node.js Brotli RCE (CVE-2026-111497): Patch Guide

Node.js CVE-2026-111497 exposes Brotli decoding to potential RCE. Check affected versions, fetch() exposure, WAF limits, and the October 2026 patch checklist.

William OGOU
15 min read
Share
On this page13 sections

Node.js CVE-2026-111497 is a high-severity out-of-bounds write in the bundled Brotli decoder that the Node.js project says can permit remote code execution (RCE). The October 21, 2026 security releases fix the flaw in Node.js 22.23.4, 24.22.1, and 26.12.1, alongside nine other vulnerabilities. Upgrade the runtime, rebuild affected artifacts, and restart or redeploy your services.

Following our PHP2Shell patch guide, this is another reminder that secure application code does not eliminate vulnerabilities in the runtime underneath it. But the exposure conditions matter: an attacker must get your Node.js process to decompress attacker-controlled Brotli data. Simply running an HTTP server does not establish that path.

This guide is for developers, platform engineers, and security teams assessing Node.js APIs, server-rendered applications, workers, and build environments. It covers the decoder risk, the other October fixes, and a practical remediation checklist not an exploit walkthrough.

Key Takeaways

  • Patch all three supported lines: Install 22.23.4, 24.22.1, or 26.12.1, or a later patched release on your supported line. Node.js rates the Brotli flaw high, not critical.
  • Review both inbound and outbound data: Explicit node:zlib decompression and automatic decoding of Brotli-compressed responses through fetch() can reach the vulnerable code.
  • Do not overstate the public exploit: The reported public proof of concept achieved code execution in a deliberately weakened local harness; its stock Node.js result was a crash and bounded memory disclosure.
  • A WAF is not a runtime patch: Inbound filtering does not protect a function that fetches a malicious Brotli response from another server.
  • Update more than npm packages: Node.js bundles Brotli and other dependencies. Updating your framework or installing a newer npm package does not replace the running Node.js binary.
  • Leave end-of-life releases behind: Node.js 20.x and earlier do not receive these upstream fixes. Move to a supported release line.

Which Node.js Versions Are Affected and Fixed?

The Node.js security advisory identifies 22.x, 24.x, and 26.x as affected supported lines. The first fixed upstream versions are:

Release lineStatus on October 22, 2026Unpatched versions in that lineFirst fixed release
Node.js 22.xLong-term support (LTS)Earlier than 22.23.422.23.4
Node.js 24.xLong-term support (LTS)Earlier than 24.22.124.22.1
Node.js 26.xCurrentEarlier than 26.12.126.12.1
Node.js 20.x and earlierEnd of lifeNo fix in this upstream releaseMigrate to a supported line

The table lists upstream versions. If your Linux distribution or commercial support vendor supplies a backported fix, verify CVE-2026-111497 against that vendor’s advisory and installed package revision rather than guessing from an older-looking version string.

Do not interpret the absence of an end-of-life branch from the supported-line list as evidence of safety. Check the Node.js release schedule, including for unsupported odd-numbered releases, and migrate rather than waiting for an upstream patch that is not scheduled.

How the Node.js Brotli Decoder Vulnerability Works

Brotli is a compression format commonly used for web content; HTTP identifies Brotli-compressed bodies with Content-Encoding: br. Node.js includes native Brotli code and exposes decompression through the node:zlib module. Libraries can call those APIs on your application’s behalf.

The vulnerability is an out-of-bounds write: malformed compressed input causes the decoder to write outside an intended memory buffer. Unlike a JavaScript validation error, corruption in native code can affect the memory of the whole Node.js process. Depending on the build and exploit, the consequences can include a process crash, memory disclosure, or potentially execution of attacker-chosen code with the process’s permissions.

The fix brings an upstream Brotli decoder patch into Node.js so invalid input is rejected before the unsafe operation. Google’s Brotli 1.2.1 changelog identifies the same CVE as an out-of-bounds write permitting RCE; the release also has backports in 1.1.1 and 1.0.10, as covered in The Hacker News reporting.

This is a dependency vulnerability, not a malicious npm package or an application-specific coding mistake. Other products that bundle vulnerable Brotli code need their own vendor assessment and update. Patching Node.js does not automatically patch a separate native application using another copy of Brotli.

Why fetch() Matters Even Without a node:zlib Import

An application does not need to call brotliDecompress() directly to be exposed. Node.js’s built-in fetch(), backed by Undici, can automatically decompress a response served with Brotli encoding. Processing that response can therefore reach the native decoder even when your source code contains no explicit Brotli API call.

For example, consider a service that fetches a user-submitted URL to generate a link preview. If an attacker controls the fetched server and its compressed response, the data crosses into the decoder through an outbound request’s response, not through the service’s inbound request body. Vercel’s advisory explicitly warns that only the runtime patch covers fetched responses.

Restricting outbound destinations remains useful defense in depth, but it is not a replacement for the patch. Even an approved integration can change behavior or become compromised.

Is Every Node.js Application Remotely Exploitable?

No. An affected runtime and a reachable attacker-controlled decompression path are different things. Assess the following data flows, including behavior inside frameworks and dependencies:

Application behaviorRelevance to CVE-2026-111497What to inspect
Decompresses Brotli request bodiesPotential inbound pathBody-parsing middleware, upload processing, and explicit zlib calls
Fetches URLs an untrusted user can influencePotential outbound-response pathLink previews, remote content importers, image processing, redirects, and HTTP client behavior
Decompresses imported files or queued messagesPotential non-HTTP pathWho can supply the bytes, and which process decodes them
Only compresses its own responsesEncoding alone does not establish this decoder pathSeparate compression from decompression; inspect other code paths too
Never decompresses attacker-controlled Brotli dataNo identified path for this specific decoder flawStill patch for the other security issues and future changes

Node.js does not automatically decompress every incoming HTTP request just because the request contains Content-Encoding: br. Your application or middleware must invoke decoding. Conversely, a worker with no public listening port may still be exposed if it consumes untrusted compressed data.

The distinction is similar to the dependency-boundary problem in MongoBleed: the security question is not just which package you use, but which untrusted bytes reach a native parser. The two vulnerabilities have different mechanics and should not be treated as interchangeable exploits.

What Has the Public Proof of Concept Actually Demonstrated?

RCE is the impact stated by the Node.js project, but it is not the same as a demonstrated portable exploit against every standard build. As of October 22, 2026, The Hacker News reports that a public proof of concept reached code execution only in a deliberately weakened test build. Against stock Node.js, the author reported a crash and limited process-memory disclosure, not successful code execution.

Patched Node.js rejects the malformed input used by that proof of concept. The same reporting says no exploitation in the wild had been reported as of October 22. That is a time-bounded observation, not a guarantee that exploitation has not occurred or will remain impractical.

This article is an advisory-based analysis, not an independent exploit reproduction. The operational decision does not require waiting for a more reliable public exploit: a reachable native memory-corruption bug and available security updates are sufficient reasons to prioritize patching.

All 10 Vulnerabilities in the October 2026 Node.js Release

The official advisory lists four high, three medium, and three low severity vulnerabilities across the supported lines. Not every issue affects every line.

CVEIssueSeverityAffected supported lines
CVE-2026-111497Brotli decoder out-of-bounds write with potential RCEHigh22.x, 24.x, 26.x
CVE-2026-106069TLS hostname-check bypass for hosts loosely resolving to an IP addressHigh22.x, 24.x, 26.x
CVE-2026-105483TLS hostname-check bypass for IP addresses written with fullwidth digitsHigh24.x, 26.x
CVE-2026-105482dns.resolve truncates names containing a NUL characterHigh22.x, 24.x, 26.x
CVE-2026-105481Keep-alive socket can process a response written before the request was sentMedium22.x, 24.x, 26.x
CVE-2026-106072Non-canonical IPv4 certificate validation lets DNS subject alternative names authenticate IP endpointsMedium22.x, 24.x, 26.x
CVE-2026-106074Randomness caches persist across startup snapshots and single-executable applicationsMedium22.x, 24.x, 26.x
CVE-2026-106070ZipFile returns attacker-controlled prefix bytes after ZIP header validation failsLow26.x
CVE-2026-106071Permission Model filesystem over-grant through wildcard lookupLow26.x
CVE-2026-106073Permission Model bypass through fs.realpathSyncLow22.x, 24.x, 26.x

Why the Randomness-Cache Bug Deserves Attention

CVE-2026-106074 concerns entropy caches used by crypto.randomUUID() and crypto.randomInt() being saved into user-land startup snapshots and single-executable applications (SEAs). Reusing those cached values across processes undermines assumptions about uniqueness or unpredictability. This is a specific artifact-generation scenario, not a claim that every ordinary Node.js process returns identical random values.

If you distribute snapshots or SEA binaries, regenerate them using the patched runtime and review whether repeated values affected identifiers or security-sensitive workflows. Merely updating a host’s separately installed Node.js does not replace the runtime embedded in an already distributed executable.

The eMudhra Certificate Block Is a Separate Reason to Upgrade

The releases also address the reported compromise of eight eMudhra/emSign intermediate certificate authority keys. Node.js embeds Mozilla’s root store but does not perform online certificate revocation checking by default. A chain involving a compromised intermediate could therefore still validate if it otherwise reached a trusted root.

Node.js adds a compiled-in public-key blocklist checked during certificate-chain verification. The accompanying NSS 3.131.1 root-store update removes three emSign roots: emSign ECC Root CA - G3, emSign Root CA - C1, and emSign ECC Root CA - C3.

There is an important limitation: TLS sessions resumed from before the upgrade are not re-verified, and that exposure ends with the session timeout. Account for session resumption and connection pools in your rollout; do not assume replacing a binary on disk revalidates established connections. If an integration fails certificate validation after patching, investigate the chain with the provider do not disable TLS verification to restore connectivity.

Bundled Dependency Updates Beyond the 10 CVEs

The October releases also update c-ares and Undici on all three supported lines, OpenSSL on 22.x and 24.x, and SQLite on 22.x, according to the Node.js advisory.

The Undici update incorporates fixes for three moderate advisories: a Subresource Integrity check issue, a memory-exhaustion issue, and a WebSocket client memory-exhaustion issue. This is another reason to deploy the complete runtime update rather than focusing only on Brotli.

Installing an updated undici npm package does not itself replace the copy backing Node.js’s built-in fetch(). Likewise, a clean application dependency scan is not proof that the runtime’s bundled native dependencies are patched.

How to Patch and Verify Your Node.js Deployments

Step 1: Inventory the Runtime That Actually Executes Your Code

Run these checks inside each deployed container, host, or equivalent execution environment not just your laptop:

bash
node --version
node -p 'JSON.stringify({ executable: process.execPath, node: process.version, brotli: process.versions.brotli, undici: process.versions.undici }, null, 2)'

These commands identify the invoked binary and its reported components; they are inventory checks, not exploit tests. A shell can select a different binary from the one an existing service uses, so correlate the output with the service configuration and running deployment. Do not publish this diagnostic output through an unauthenticated endpoint.

Check container build and final runtime stages, self-hosted servers, serverless settings, CI runners, developer machines, snapshots, and vendor-distributed executables. Node.js can cherry-pick a security patch without adopting a new upstream Brotli version number, so process.versions.brotli alone is not a reliable pass/fail test.

Step 2: Upgrade the Binary and Rebuild Affected Artifacts

Use your approved package manager, runtime manager, container-image source, or hosting-provider workflow to install a fixed release. For an existing 22.x or 24.x deployment, a patched release on the same supported major line generally minimizes compatibility changes; an EOL deployment needs a supported-line migration.

For containers, update the base image reference and verify the image actually contains the fixed runtime before rebuilding. Refresh your approved digest pins, rebuild all affected stages, and redeploy the resulting application image. A tag change in a Dockerfile does nothing for containers that are already running.

For snapshots and SEAs, rebuild the distributed artifacts too. Updating package.json’s engines.node, a lockfile, or the local framework version is not evidence that production has switched binaries. Keep container least-privilege controls in place as described in our Docker Hardened Images guide, but treat hardening as blast-radius reduction rather than a fix.

Step 3: Restart or Redeploy, Then Check Every Replica

Replace all long-running workers with processes launched from the patched runtime. Verify the active release and image digest across every replica, job template, region, and rollback target. Otherwise, autoscaling or a rollback can silently restore an unpatched image.

Exercise legitimate Brotli response handling, outbound integrations, TLS connections, and snapshot-based startup in staging. Confirm certificate failures are understood rather than bypassed. Track the deployment revision and runtime version as evidence that remediation reached the workloads, not merely the build configuration.

Step 4: Confirm Managed-Hosting Coverage Instead of Assuming It

Vercel says it deployed inbound WAF protection on October 21 and is rolling patched versions across its managed runtimes. Projects selecting Node.js 22.x or 24.x do not need to change their major-version setting; Vercel manages patch versions. Check the provider’s rollout status and the runtime used by your deployed functions.

Projects still selecting 20.x must switch to 22.x or 24.x and redeploy. External backends, self-hosted Next.js instances, and containers remain your responsibility even when their inbound traffic passes through Vercel.

What If You Cannot Upgrade Immediately?

The Node.js advisory does not provide a temporary workaround for the Brotli decoder flaw. Upgrading is the fix. Any interim controls should be documented as exposure reduction with an owner and a short patch deadline.

Where your architecture permits, stop affected features from consuming untrusted Brotli input while you prepare the rollout. Review compressed-body middleware, remote URL importers, redirects, and background jobs. An inbound rule rejecting compressed request bodies does not cover a response received by an outbound HTTP client, nor does it cover compressed files processed later.

Request size limits, rate limits, and decompressed-output limits can help with resource-exhaustion risks, but they do not establish safety from this memory-corruption flaw. Changing Accept-Encoding is not a verified security boundary: a remote server can send a compressed response anyway. A JavaScript try/catch cannot reliably contain native memory corruption.

Vercel’s WAF rules are useful for covered inbound traffic, but they do not inspect responses your functions fetch from other servers. Do not treat a green firewall dashboard as proof that a vulnerable decoder is unreachable.

Detection and Remediation Checklist

There is no universal log signature established by the cited advisory. Unexpected native crashes, SIGSEGV events, repeated decoder errors, or worker restarts after compressed input are investigation leads not proof of exploitation. Correlate process telemetry with request handling, outbound destinations, response encodings, and deployment versions; avoid logging sensitive response bodies just to troubleshoot.

If suspicious execution or memory access is supported by evidence, preserve relevant logs and crash artifacts, isolate the workload, and follow your incident-response process. Review secrets accessible to the Node.js process and rotate them according to the assessed exposure. Being on an affected version alone does not prove that all credentials were stolen.

Use this checklist to close the patching task:

  • Inventory all Node.js runtimes, including CI, serverless functions, snapshots, and embedded executables.
  • Upgrade to 22.23.4, 24.22.1, 26.12.1, or a verified later patched release/vendor backport.
  • Migrate EOL deployments to a supported line.
  • Rebuild images, snapshots, and single-executable applications.
  • Restart or redeploy all workers and confirm the active runtime across replicas.
  • Replace vulnerable autoscaling templates and rollback artifacts.
  • Review both inbound decompression and outbound Brotli response handling.
  • Validate TLS integrations and account for pre-upgrade session resumption.
  • Record WAF coverage separately from proof of runtime remediation.

Conclusion: Patch the Runtime, Not Just the Request Path

CVE-2026-111497 makes attacker-controlled Brotli decoding a runtime-level security concern across all supported Node.js lines. The public exploit evidence has limits, but those limits do not justify leaving a reachable memory-corruption bug unpatched. The same releases also fix TLS, DNS, randomness-cache, and Permission Model issues and block compromised CA keys.

The lesson after PHP2Shell is practical: add runtimes and their bundled dependencies to your patch inventory, not just application packages. Deploy Node.js 22.23.4, 24.22.1, or 26.12.1, verify the actual running workloads, and remember that an outbound response can reach the vulnerable decoder without ever passing through your inbound WAF.

For help strengthening your cloud security and runtime patching strategy, connect with me on LinkedIn or email [email protected].

FAQ

Frequently Asked Questions (FAQ)

What is CVE-2026-111497 in Node.js?

CVE-2026-111497 is a high-severity out-of-bounds write in the Brotli decoder bundled with Node.js. The Node.js project says it can permit remote code execution. Exposure requires a Node.js process to decompress attacker-controlled Brotli data, directly through zlib or indirectly through a library or HTTP client.

Which Node.js versions fix the Brotli vulnerability?

The first fixed upstream versions are Node.js 22.23.4, 24.22.1, and 26.12.1, released on October 21, 2026. Install one of these or a later patched release on your supported line. Node.js 20.x and earlier do not receive these upstream fixes and should be migrated.

Can Node.js fetch() reach the vulnerable Brotli decoder?

Yes. Built-in fetch() can automatically decompress Brotli-encoded HTTP responses. If an attacker controls a fetched response, processing it can reach the bundled decoder even without an explicit zlib import. This outbound-response path is not covered by an inbound web application firewall.

Does updating npm packages or Next.js fix CVE-2026-111497?

Not by itself. The vulnerable Brotli code is bundled with the Node.js runtime. Update the binary or the container or managed runtime that executes the application, then restart or redeploy. Regenerate startup snapshots and single-executable applications built with an affected runtime too.

Has the Node.js Brotli flaw been exploited in the wild?

As of October 22, 2026, the cited reporting says no in-the-wild exploitation had been reported. The public proof of concept demonstrated code execution in a deliberately weakened harness, and a crash plus limited memory disclosure on stock Node.js. That does not establish universal stock-build RCE or remove the need to patch.

Is there a workaround if I cannot upgrade Node.js yet?

The Node.js advisory provides no temporary Brotli workaround. Restricting untrusted compressed input and using provider WAF rules can reduce specific exposure, but neither replaces patching. Inbound WAF protection does not cover Brotli responses fetched from other servers, and compression headers are not a reliable substitute for the runtime fix.

Resources