CVE-2026-111497: Inside Node2Shell and the Brotli Decoder Flaw - Safe Security

CVE-2026-111497: Inside Node2Shell and the Brotli Decoder Flaw

Oct 26, 2026 11 minute read

By SAFE Threat Research Team

A vulnerability first surfaced through Node.js has exposed a much broader attack surface in one of the web ecosystem’s most widely embedded compression components.

CVE-2026-111497 is an out-of-bounds write in Google’s Brotli decoder. A specially crafted Brotli stream can push the decoder into an invalid internal state, in which malformed input is treated as though more data is still required. Processing continues when it should have stopped, allowing attacker-controlled data to cross a memory boundary inside the decoder.

A crash is the simplest outcome. The same primitive can also expose process memory and, under the right memory layout conditions, be exploited to enable remote code execution.

What makes this vulnerability particularly significant is where that decoder lives.

Brotli is not confined to Node.js. The affected implementation has been incorporated into language runtimes, HTTP clients, proxies, service meshes, developer tooling, and other software that processes compressed content. As vendors audited their own dependencies, the affected surface area expanded across Node.js, Bun, Python packages, Envoy, Istio, .NET, and other applications that use the same decoder.

And the attack path works in both directions.

An attacker may send malicious Brotli content directly to a server that decompresses incoming requests. But an internal service can also expose itself by fetching an attacker-controlled URL and decompressing the response. A crawler, URL-preview service, webhook processor, scanner, or integration service can therefore become reachable without exposing the vulnerable decoder directly to the internet.

That changes the enterprise question from:

“Where are we running vulnerable Node.js versions?” 

to:

“Where can attacker-controlled Brotli data reach a vulnerable decoder, and what does that process have access to if exploitation succeeds?”

Vulnerability At a Glance

CVE CVE-2026-111497
Affected component Google Brotli decoder
CWE CWE-787 – Out-of-bounds Write; CWE-252 – Unchecked Return Value
Severity Critical
CVSS score 9.2 (CVSS v4.0)
CVSS vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Privileges required None
User interaction None
Primary prerequisite Attacker-controlled Brotli data reaches a vulnerable decoder
Potential impact Denial of service, process-memory disclosure, remote code execution
Affected Brotli versions 1.0.3 through 1.2.0
Exploitation status No confirmed successful in-the-wild exploitation has been publicly reported at the time of writing. Public PoCs and exploit research are available, and defensive signatures for exploitation attempts have already been released.

What actually breaks

The vulnerability sits in Brotli’s streaming decompression logic.

A decoder normally has to distinguish between two very different conditions:

  • A valid stream is incomplete and needs more input
  • The stream has entered an invalid state, and processing must stop

CVE-2026-111497 breaks that distinction.

A specially constructed Brotli stream drives the decoder into an invalid block-switch state. Instead of rejecting it as malformed, the affected implementation reports a condition equivalent to “need more input.”

Processing, therefore, continues.

Malformed Brotli stream
|
v
Invalid decoder state
|
+---- Expected
| |
| v
| FORMAT ERROR
| Stop
|
+---- Vulnerable
|
v
NEED MORE INPUT
|
v
Continue decoding
|
v
Out-of-bounds write

Node.js describes the affected path as continuing into an eight-byte internal decoder buffer until subsequent attacker-controlled input crosses the intended memory boundary. 

The patched decoder changes this behavior at the state transition itself: the impossible condition becomes a hard format error instead of a recoverable input condition.

That is what turns a relatively small decoder-state error into a security boundary failure:

Malformed compressed data → incorrect decoder state → out-of-bounds memory write.

Impact: From a Crash to Code Execution

The out-of-bounds write is the exploitation primitive. What happens next depends on which process memory is corrupted and how much control an attacker can establish over that corruption.

Denial of Service

The easiest outcome is a crash. A malicious Brotli stream reaches the decoder, memory is overwritten, and the operating system terminates the process after an invalid memory access.

The validation captured in the original research reproduced this against a stock vulnerable Node.js instance. The process terminated with SIGSEGV, and Docker reported exit code 139. Replaying the same input against Node.js 24.22.1 produced a controlled decoder error instead.

Figure 1: A crafted Brotli stream terminates the vulnerable Node.js process. The patched build handles the same malformed input as a normal decoder error.

In Kubernetes or another orchestrated environment, automatic restarts can mask the underlying condition:

Malicious input
↓
Application crashes
↓
Pod restarts
↓
Attacker retries
↓
Crash loop / degraded availability

The vulnerability, therefore, provides a remote denial-of-service primitive. Whether that becomes a distributed denial-of-service event depends on how attackers deliver the traffic.

Process Memory Disclosure

The impact is not limited to the termination of the process. Because the vulnerability corrupts native memory, affected advisories also identify process-memory disclosure as a potential consequence.

Depending on the application, that process may contain:

  • Authentication or session tokens
  • Database connection strings
  • API credentials
  • Application secrets
  • Cloud credentials
  • Sensitive request data

That makes memory disclosure meaningful even when full RCE cannot be achieved reliably.

Remote Code Execution

RCE raises the exploitation bar considerably. A crash only requires memory corruption to destabilize the process. Code execution requires an attacker to corrupt something useful – such as a callback, object, pointer, or execution-relevant structure – and reliably redirect program flow.

Conceptually:

Out-of-bounds write
↓
Shape process memory
↓
Corrupt useful structure
↓
Control execution flow
↓
Attacker-controlled execution

Public research has demonstrated code execution on vulnerable Node.js deployments, including Node.js 24.22.0 on Linux arm64. The exploit was not reliable across every attempt, reinforcing that while the memory-corruption primitive is confirmed, practical RCE depends on the target runtime, architecture, heap state, and application layout.

Figure 2: Successful exploitation executes a command in the security context of the vulnerable Node.js process, demonstrating that the memory corruption can be leveraged beyond a crash to gain execution control.

This distinction is important:

A vulnerable Brotli decoder provides a real RCE-capable memory-corruption primitive. It does not make every affected installation an immediately reliable remote shell.

Why RCE Matters Beyond the Application Process

Successful exploitation initially gives the attacker the privileges of the affected process. That may sound constrained, but modern enterprise applications rarely operate in isolation. A compromised application process may already have access to:

Application process
|
+-- Database credentials
+-- API tokens
+-- JWT secrets
+-- Cloud identity
+-- Mounted secrets
+-- Internal services
+-- Kubernetes service account

CVE-2026-111497 does not itself provide those additional privileges. It provides the foothold from which existing application trust can potentially be abused.

That makes the identity and connectivity of the affected workload central to prioritization. A low-privilege isolated service and a service holding broad cloud credentials may carry the same CVE, but they do not represent the same enterprise risk.

Attack Scenarios

The most important characteristic of CVE-2026-111497 is that attacker-controlled Brotli can reach the decoder from either direction.

Scenario 1: Attacker → Server

The direct attack path occurs when an application accepts and decompresses Brotli-encoded input.

Attacker
|
| Content-Encoding: br
v
Reverse proxy / application
|
v
Request decompression
|
v
Vulnerable Brotli decoder
|
+-- Crash
+-- Memory disclosure
└-- Potential RCE

Framework or middleware handling may decompress the body before the request reaches normal application logic.

That can make the vulnerable operation reachable before:

  • Route processing
  • Application authorization
  • Business-logic validation

Scenario 2: Server → Attacker

The second attack path is less obvious.

Consider a service that provides URL previews:

POST /preview

{
"url": "https://attacker.example/page"
}

The enterprise application makes the outbound request.

The attacker controls the response:

HTTP/1.1 200 OK
Content-Encoding: br

<malicious Brotli data>

The attack path becomes:

User-controlled URL
↓
Enterprise service
↓
Outbound HTTP request
↓
Attacker-controlled server
↓
Malicious Brotli response
↓
Enterprise service decompresses response
↓
Vulnerable decoder

That pattern is relevant to:

  • URL-preview services
  • Web crawlers
  • Link unfurlers
  • Webhook processors
  • Remote-import functions
  • Website scanners
  • Integration services
  • CI/CD workers
  • Software-analysis tooling

This means internet-facing status alone is not enough to determine exposure.

An internal service can be exploitable if an external attacker can influence the data it retrieves.

The security question, therefore, becomes:

Can an attacker influence the bytes reaching this decoder?

rather than simply:

Can the attacker connect directly to this host?

Impact Beyond Node.js

The “Node2Shell” name captures where the vulnerability initially received attention, but not where the vulnerable code actually exists.

The issue originates in Google’s Brotli implementation, which has been incorporated into multiple runtimes and products.

Product / Component Affected Version / Condition Fixed Version
Google Brotli 1.0.3 through 1.2.0 1.0.10 / 1.1.1 / 1.2.1
Node.js Affected releases in 22.x, 24.x and 26.x 22.23.4 / 24.22.1 / 26.12.1
Bun 1.0.21–1.4.3 1.4.4
Python Brotli ≤1.2.0 1.2.1
Python brotlicffi ≤1.2.0.x 1.2.1.0
Envoy Affected supported releases where Brotli decompression is enabled Fixed releases across supported branches
Istio Affected releases with Brotli decompression enabled 1.31.2 / 1.30.6; 1.29.9 contains the fix on the now-EOL branch
cdxgen @cdxgen/cdxgen ≤13.4.0; @cyclonedx/cdxgen ≤12.8.8 in affected standalone deployments 13.5.0 / 12.8.9
.NET 8 <8.0.33 under affected Brotli usage 8.0.33
.NET 9 <9.0.22 9.0.22
.NET 10 <10.0.14 10.0.14
.NET 11 preview Earlier affected preview builds 11.0.0-rc.3.26522.148

Envoy is affected when the Brotli decompressor is configured; its advisory describes potential memory disclosure, denial-of-service, and arbitrary code execution arising from corrupted decoder state.

Python’s Brotli and brotlicffi packages embed the affected implementation, thereby extending exposure for Python applications that pass untrusted Brotli data to those libraries. 

Microsoft disclosed .NET exposure on October 25. Importantly, default HttpClient and ASP.NET Core configurations do not automatically make every .NET application vulnerable; exposure depends on Brotli decompression being explicitly used or enabled for attacker-controlled data. 

The list may also extend beyond software with a direct package dependency.

Brotli can be:

  • Statically linked into a binary
  • Bundled into a runtime
  • Embedded inside a container
  • Included transitively through another library
  • Shipped inside third-party software

That creates an inventory challenge: the vulnerable component may exist several layers below the product visible in the CMDB.

How Enterprises Should Respond

1. Patch first

The durable fix is to replace the vulnerable decoder.

For Node.js, upgrade to:

  • 22.23.4 or later
  • 24.22.1 or later
  • 26.12.1 or later

2. Block Brotli request bodies where they are not needed

For applications with no requirement to accept Brotli-compressed requests, reject:

Content-Encoding: br

at the API gateway, reverse proxy, WAF, or application layer. This can break the direct attacker-to-server path while patching is underway.

3. Restrict attacker-controlled outbound fetches

URL previews, crawlers, scanners, webhook services, and remote-import functionality should have constrained outbound connectivity.

Controls can include:

  • Destination allowlists
  • Egress filtering
  • Redirect validation
  • Protocol restrictions
  • Segmentation of fetching workloads

These controls are particularly relevant to the server-to-attacker exploitation path.

4. Disable unnecessary automatic Brotli decompression

Where operationally feasible, applications can temporarily stop Brotli responses from untrusted origins from automatically decompressing.

5. Reduce post-exploitation privilege

Limit the blast radius of a successful RCE by restricting:

  • Cloud IAM permissions
  • Kubernetes RBAC
  • Service-account privileges
  • Mounted secrets
  • Database permissions
  • Filesystem access
  • Internal network reachability

6. Hunt for crash and execution signals

Useful telemetry includes:

  • Unexpected SIGSEGV
  • Container exit code 139
  • Repeated application restart loops
  • Crashes immediately following Brotli processing
  • Unusual Content-Encoding: br request patterns
  • Decoder failures following outbound HTTP retrieval
  • Unexpected shell or child-process creation from affected application runtimes

Closing: The Decoder Is the Vulnerability. The Data Path Determines the Risk.

CVE-2026-111497 is easy to reduce to “another Node.js RCE.”

That misses the important part.

The vulnerable code sits below the application layer, inside a component that different runtimes and products have quietly embedded for years. Whether it becomes exploitable depends on what reaches that decoder and what the hosting process can do afterward.

A public API that accepts compressed request bodies, an internal URL-preview service that retrieves attacker-controlled content, and an isolated application with no untrusted Brotli path may all contain the same vulnerable code.

They do not carry the same risk.

The priority is therefore the intersection of:

Vulnerable decoder × attacker-controlled data path × consequential workload privilege.

That is the distinction security teams need to make quickly as vulnerabilities propagate through shared components and multiple product ecosystems.

SAFE CTEM helps teams make that shift from CVE presence to exposure context – connecting vulnerable assets with reachability, exploitability, controls, and business impact so remediation starts where compromise can create the most material risk.

For CVE-2026-111497, the fix is straightforward: remove the vulnerable Brotli decoder from the attack path.

The harder and more important question is which systems an attacker can actually reach before that patch lands.

See how SAFE transforms your CTEM Unified exposure visibility, AI-driven prioritization, and quantified risk in business terms. Built for enterprise scale.