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.


On this page
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:zlibdecompression and automatic decoding of Brotli-compressed responses throughfetch()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 line | Status on October 22, 2026 | Unpatched versions in that line | First fixed release |
|---|---|---|---|
| Node.js 22.x | Long-term support (LTS) | Earlier than 22.23.4 | 22.23.4 |
| Node.js 24.x | Long-term support (LTS) | Earlier than 24.22.1 | 24.22.1 |
| Node.js 26.x | Current | Earlier than 26.12.1 | 26.12.1 |
| Node.js 20.x and earlier | End of life | No fix in this upstream release | Migrate 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 behavior | Relevance to CVE-2026-111497 | What to inspect |
|---|---|---|
| Decompresses Brotli request bodies | Potential inbound path | Body-parsing middleware, upload processing, and explicit zlib calls |
| Fetches URLs an untrusted user can influence | Potential outbound-response path | Link previews, remote content importers, image processing, redirects, and HTTP client behavior |
| Decompresses imported files or queued messages | Potential non-HTTP path | Who can supply the bytes, and which process decodes them |
| Only compresses its own responses | Encoding alone does not establish this decoder path | Separate compression from decompression; inspect other code paths too |
| Never decompresses attacker-controlled Brotli data | No identified path for this specific decoder flaw | Still 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.
| CVE | Issue | Severity | Affected supported lines |
|---|---|---|---|
| CVE-2026-111497 | Brotli decoder out-of-bounds write with potential RCE | High | 22.x, 24.x, 26.x |
| CVE-2026-106069 | TLS hostname-check bypass for hosts loosely resolving to an IP address | High | 22.x, 24.x, 26.x |
| CVE-2026-105483 | TLS hostname-check bypass for IP addresses written with fullwidth digits | High | 24.x, 26.x |
| CVE-2026-105482 | dns.resolve truncates names containing a NUL character | High | 22.x, 24.x, 26.x |
| CVE-2026-105481 | Keep-alive socket can process a response written before the request was sent | Medium | 22.x, 24.x, 26.x |
| CVE-2026-106072 | Non-canonical IPv4 certificate validation lets DNS subject alternative names authenticate IP endpoints | Medium | 22.x, 24.x, 26.x |
| CVE-2026-106074 | Randomness caches persist across startup snapshots and single-executable applications | Medium | 22.x, 24.x, 26.x |
| CVE-2026-106070 | ZipFile returns attacker-controlled prefix bytes after ZIP header validation fails | Low | 26.x |
| CVE-2026-106071 | Permission Model filesystem over-grant through wildcard lookup | Low | 26.x |
| CVE-2026-106073 | Permission Model bypass through fs.realpathSync | Low | 22.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:
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
- Node.js Project: October 21, 2026 security advisory and all 10 CVEs
- Fixed upstream releases: Node.js 22.23.4, 24.22.1, and 26.12.1
- Google Brotli: Version 1.2.1 security changelog
- Vercel Security Team: Node.js Brotli advisory, managed-runtime actions, and WAF limitations
- Node.js certificate changes: Blocked intermediate public keys and emSign root removals
- The Hacker News: October 22 coverage and public proof-of-concept limitations



