Skip to main content
Blog

Node2Shell: Brotli Decoder Memory Corruption and Enterprise Exposure

  • Nov 3, 2026 6:35 PM UTC
  • 0 replies
  • 2 views
  • Translate All
Dheeraj Kumar
Forum|alt.badge.img

Executive Assessment:

CVE-2026-111497, also referred to as Node2Shell, HTTP2Shell, or Broccoli2Shell, is an out-of-bounds write vulnerability affecting the Brotli decoder bundled with Node.js and used in other software. The flaw originates in the decoder's handling of malformed block switches. Instead of rejecting an invalid stream, the affected code incorrectly signals that additional input is required. As processing continues, incoming data can accumulate in an eight-byte internal buffer and eventually cause an out-of-bounds write. The resulting memory corruption may lead to process crashes, memory disclosure, or remote code execution (RCE). The vulnerability and its underlying cause are documented in the Node.js security advisory and upstream source changes.

Exposure depends on whether an attacker can supply crafted Brotli-compressed data to a vulnerable decoder. Node.js does not automatically decompress all incoming HTTP requests, so the presence of an affected runtime alone does not establish remote exploitability. Applications may become exposed through direct use of node:zlib, request parsers configured to decompress Brotli-encoded bodies, or the built-in 'fetch()' functionality when processing responses containing 'Content-Encoding: br'. The actual attack surface depends on application configuration, middleware execution order, authentication controls, access to external URLs, response-body processing, and the decoder version running in the deployed environment. These conditions must be assessed individually when determining which services are exposed.

The vulnerability carries a CVSS 4.0 score of 9.2 (Critical) and a CVSS 3.1 score of 9.8 (Critical) in the NVD, while the Node.js project rates its severity as High. Public researchers reported controlled demonstrated RCE against selected vulnerable Node.js builds, confirming that exploitation can extend beyond process disruption. CISA records the vulnerability as actively exploited, with its addition to the Known Exploited Vulnerabilities (KEV) catalog on 27 October 2026. A separate public sensor report identified exploit traffic on 26 October 2026. Taken together, these findings establish demonstrated code execution under controlled conditions and evidence of exploitation attempts in the wild. However, the reviewed public information does not confirm a successful compromise of a production environment, establish exploit reliability across different platforms, or identify a responsible threat actor.

Vulnerability Profile and Affected Builds:

Attribute 

Analyst assessment 

Identifier / common name

CVE-2026-111497 / Node2Shell

Affected component

Brotli C streaming decoder, including builds embedded in Node.js or bundled with other software

Weakness

CWE-787 out-of-bounds write, enabled by failure to propagate an error result (CWE-252)

Severity

Node.js project rating: High. Published CVSS: v4.0 9.2 Critical; v3.1 9.8 Critical.

Impact

Process crash, possible process-memory disclosure, or code execution with the decoder process's privileges

Exploit prerequisite

Attacker-controlled or attacker-influenced compressed bytes reach the vulnerable decoder

Supported Node.js fixes 

22.23.4; 24.22.1; 26.12.1 (or later fixed builds on the relevant supported line)

Upstream Brotli fixed releases

1.0.10; 1.1.1; 1.2.1 (for the corresponding affected release families)

The affected supported Node.js ranges are 22.x before 22.23.4, 24.x before 24.22.1, and 26.x before 26.12.1. Discontinued lines should be migrated to supported releases rather than assumed safe. For upstream decoder builds, published affected ranges are 1.0.3–1.0.9, 1.1.0, and 1.2.0. Component-level vulnerability and application-level exploitability should remain separate inventory fields. 

The CVSS 4.0 vector includes AT:P (an attack requirement), consistent with an application needing a reachable decode path. The CVSS 3.1 vector uses a different model. Neither numeric score substitutes for testing which untrusted inputs the deployed service actually decompresses. 

Published CVSS vectors: 

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 
CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H 

Technical Root Cause:

Decoder state and error propagation

A streaming Brotli decoder processes block-type metadata, Huffman trees, lengths, and buffered input over successive chunks. It must distinguish an incomplete chunk, which requires additional bytes, from a malformed stream, which must be rejected. In the vulnerable path, an invalid block switch was handled like incomplete input. A caller could therefore continue feeding data after the decoder had entered an inconsistent state.

The upstream change replaces ambiguous boolean results with explicit "BrotliDecoderErrorCode" statuses. An invalid switch now returns "BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"; a genuine input shortage still returns "BROTLI_DECODER_NEEDS_MORE_INPUT". The block-switch helpers propagate those results into the processing loop, which stops decoding on a format error instead of retaining an invalid state.

Before the correction, the continuation path could retain and append input to an eight-byte internal buffer without draining it as expected. Subsequent handling could cross the buffer boundary. The root cause is therefore error-state confusion within the decoder, not a missing size check in a particular JavaScript route. A request-size limit cannot repair that state transition.

Security consequence

Memory corruption occurs inside the process performing decompression. Any achieved code execution inherits that process identity, permissions, available secrets, and network access. It does not inherently escalate the operating-system privilege level. This is why service isolation and minimal permissions reduce consequences but do not replace a decoder fix.

  • Condensed vulnerable sequence: untrusted Brotli input → invalid block switch accepted as incomplete input → decoder continues in an inconsistent state → out-of-bounds write → possible crash, disclosure, or code execution.

Exploitation Paths and Required Conditions:

A vulnerable Node.js process is not necessarily an exploitable service. The entry point must cause the process to decode attacker-influenced Brotli bytes. The relevant paths differ in network direction, authorization boundary, and owning workload.

Path 

Conditions to verify 

Process at risk / useful evidence 

Inbound HTTP body 

A reachable route accepts Content-Encoding: br; a configured body parser inflates it; authorization either follows parsing or does not restrict the route. 

Request-serving process; route/error context, restart events, unexpected children or egress. 

Outbound HTTP response 

A feature fetches an attacker-influenced or compromised destination; the response is Brotli-encoded and its body is consumed. 

Fetching service or worker; source request, fetched URL, decode activity, and subsequent process/network anomalies. 

Direct application decode 

An upload, queued record, cache entry, or stored object holds untrusted compressed bytes passed to a Brotli decoding API. 

Consumer process; object provenance, job failures, repeat attempts, process lineage. 

Proxy or intermediary 

A separate proxy or ingress workload uses an affected decoder with decompression enabled. 

Proxy workload rather than the backend application; crashes, request errors, or unexpected host activity. 

Node.js exposes Brotli decompression through 'node:zlib' APIs. The built-in 'fetch()' client may decompress responses carrying 'Content-Encoding: br'. Request-body inflation is framework- and middleware-dependent; a plain HTTP listener does not automatically decode all compressed bodies. For inbound paths, confirm whether parsing occurs before route authorization. For outbound paths, trace who controls the destination and whether response bytes are actually consumed.

Published studies report code execution on selected official Node.js builds, including tests on more than one processor architecture. Some demonstrations required repeated attempts. Those results establish feasibility in their test environments, not a predictable success rate across every allocator, operating system, build, or application.

Enterprise Exposure and Inventory Priorities:

Inventory should identify both the running vulnerable component and the specific data path reaching it. A dependency scan or software bill of materials can flag possible exposure; it cannot establish that remote input reaches a decode operation. Conversely, a vulnerable decoder may be embedded in an executable, container layer, language binding, or intermediary and absent from the operating system package inventory.

Environment 

Exposure discriminator 

Response priority 

Internet-facing Node.js service 

Untrusted request body is Brotli-inflated before authorization, or on an unauthenticated route. 

Critical review: confirm runtime, route, parser order, and deployment digest. 

Remote-content processor 

A webhook, URL preview, crawler, or callback can reach attacker-influenced content that the service Brotli-decodes. 

Critical review when destination control and permissive egress coexist. 

File / queue / object worker 

Untrusted compressed data enters batch processing or retry loops. 

High when cross-tenant or publicly supplied data is processed. 

Gateway / proxy / mesh 

A separate runtime is configured to decompress inbound or upstream Brotli payloads. 

High for public gateways; audit independently of the app image. 

Container / compiled runtime 

Decoder is bundled in an image, static binary, runtime layer, or serverless deployment. 

Verify deployed build; rebuild and restart even if the host library was patched. 

Encoder-only or raw HTTP path 

The assessed code path does not invoke a Brotli decoder on untrusted bytes. 

Lower immediate path priority; retain for inventory and routine updates. 

Several downstream ecosystems published their own fixes because they ship or load affected decoder code. Their advisories establish product-specific version requirements; one generic upstream version check is not enough when libraries are vendored or patched through distribution backports. The reference list identifies relevant downstream advisories without making their product branding part of the exposure narrative.

A useful asset record therefore includes: live runtime version; image or executable digest; source of the linked decoder; input provenance; request/response decompression settings; authentication or destination controls; service privileges; and whether telemetry covers process execution and network connections. This is sufficient to separate “installed” from “reachable.”

Securonix ThreatWatch Summary:

Securonix assesses with high confidence that exposure to CVE-2026-111497 depends on whether attacker-controlled Brotli data reaches a vulnerable decoder, rather than the presence of an affected runtime alone. Internet-facing applications that decompress incoming requests remain a priority, but services that retrieve and process external content introduce an equally important exposure path. This includes applications that consume Brotli-compressed responses from attacker-influenced destinations, even when their public endpoints do not support request decompression. Organizations should examine how compressed data enters each workload through HTTP requests, outbound responses, files, and background processing. Runtime inventory is a useful starting point, but actual decoder usage and input accessibility should determine remediation priority.

Published research has demonstrated remote code execution against selected vulnerable builds, establishing the feasibility of exploitation with high confidence. The reliability of these techniques across different platforms and deployment configurations remains undetermined. Another concern is that memory corruption may occur without a visible decoder exception or application error. As a result, the absence of Brotli-related errors cannot be used to rule out exploitation. Detection efforts should focus on affected workloads with reachable decompression paths and investigate unusual process execution, service instability, or unexpected network activity occurring around suspicious input.

The addition of CVE-2026-111497 to the Known Exploited Vulnerabilities catalog, together with publicly reported exploit traffic, supports treating this vulnerability as an active threat. Organizations should prioritize patching exposed services and review relevant telemetry from the disclosure period onward. Although the available evidence establishes exploitation activity, it does not confirm widespread compromise or identify a responsible threat actor. Securonix recommends correlating application, endpoint, and network evidence before determining whether an observed attempt resulted in successful code execution.

Threat Detection and Retrospective Hunting:

Detection methodology

Ordinary 'Content-Encoding: br' traffic is not malicious by itself, and typical access logs do not retain enough bytes to identify the malformed stream. A decoder can also corrupt memory without immediately producing an application-visible exception or process crash. Detection should therefore treat errors and restarts as possible pivots, not mandatory prerequisites. Higher-confidence cases combine affected runtime evidence, a reachable decode path, and unusual execution or network behavior tied to the same workload and time period.

  1. Node.js parent spawning a command interpreter

Purpose: Detect unusual interpreter creation from a Node.js process. Needs: parent/child process names, host identity, timestamp, and preferably executable paths, command lines, service user, and container identity. 

index = activity AND 
( 
  (rg_functionality = "Microsoft Windows" AND sourceprocessname CONTAINS "node.exe") 
  OR (rg_functionality = "Unix / Linux / AIX" AND sourceprocessname CONTAINS "node") 
) 
AND 
( 
  destinationprocessname CONTAINS "cmd.exe" 
  OR destinationprocessname CONTAINS "powershell" 
  OR destinationprocessname CONTAINS "pwsh" 
  OR destinationprocessname CONTAINS "bash" 
  OR destinationprocessname CONTAINS "dash" 
  OR destinationprocessname CONTAINS "sh" 
)

Triage: Inspect full executable paths and command lines; confirm whether the action is normal for that service. Build tooling, task runners, maintenance jobs, and shell-driven applications are expected false positives. The query intentionally omits a bare `sh` substring because it can match unrelated names. Add exact shell-name matching only after confirming local field semantics. Correlate with route activity, fetched content, and runtime version. 

  1. Secondary utilities launched by Node.js

Purpose: Surface Node.js processes spawning transfer tools or secondary runtimes. Needs: process ancestry and destination command line.

index = activity AND sourceprocessname CONTAINS "node" 

AND ( 

  destinationprocessname CONTAINS "curl" 

  OR destinationprocessname CONTAINS "wget" 

  OR destinationprocessname CONTAINS "socat" 

  OR destinationprocessname CONTAINS "python" 

  OR destinationprocessname CONTAINS "perl" 

  OR destinationprocessname CONTAINS "ruby" 

)

Triage: Baseline command lines per service, especially build and media-processing workloads. Tool names alone are weak evidence; utilities may be renamed, and in-process network activity will not appear here. Review recent file writes, network destinations, deployment changes, and whether the parent is the actual service process.

  1. Rare or new Node.js egress

Purpose: Find destinations attributed to Node.js processes for comparison with approved service dependencies. Needs: host/process identity and destination address.

index = activity AND sourceprocessname CONTAINS "node" 

AND destinationaddress != "unknown" 

| STATS devicehostname sourceprocessname destinationaddress 

Triage: Investigate destinations new to the workload, particularly when a recent request or background decode operation can be identified. Normal API calls, telemetry, service communication, and package retrieval generate substantial background activity. Shared gateways and network address translation can obscure origin; correlate using pod/container identifiers if collected. 

  1. Brotli-encoded inbound request exposure

Purpose: Identify ingress events that may reach a request-body decoder. This hunt scopes possible exposure; it does not identify an exploit attempt. Needs: parsed request content-encoding field or retained request headers.

index = activity 

AND rg_name = "<verified ingress source>" 

AND rawevent CONTAINS "content-encoding" 

AND rawevent CONTAINS "br" 

Triage: The raw-text pattern is intentionally broad and may match `br` elsewhere in an event. Prefer an exact comparison against a normalized content-encoding field when available; otherwise inspect each candidate request. Confirm the endpoint has Brotli body inflation enabled, the parser runs before or after authorization, and the application runtime was affected at the event time.

  1. Decoder errors, termination, and restart loops

Purpose: Review application decoder failures and nearby process or container termination events. Needs: an application log source and platform restart events. Important: absence of errors does not rule out corruption.

index = activity 

AND rg_name = "<verified app-log source>" 

AND ( 

  message CONTAINS "Brotli" 

  OR message CONTAINS "zlib" 

  OR message CONTAINS "decoder" 

)

Triage: Look for clustered failures tied to particular routes, input objects, or jobs; compare with process lineage and egress. Expected decode errors, invalid client data, software bugs, and routine deployments can produce the same log text. Validate whether application messages are indexed in `message` or only in raw events before using the template.

Mitigation and Defensive Recommendations:

Immediate remediation

  • Organizations should upgrade affected Node.js runtimes to the fixed releases 22.23.4, 24.22.1, or 26.12.1, or later patched versions within the respective supported branches. Deployments running discontinued versions should be migrated to supported releases.

  • Review all applications and infrastructure components that contain the vulnerable Brotli decoder, including native libraries, language bindings, container images, gateways, and statically linked executables. Embedded decoder copies require separate attention, as updating the operating system or host-level package may leave vulnerable components unchanged. Apply the appropriate fixes based on the affected component and its supported release.

  • After applying the updates, rebuild and redeploy affected applications and restart their running processes. Verify the deployed runtime version, container image digest, and active process to confirm that the patched decoder is in use. Package updates alone do not replace vulnerable components already running in deployed workloads.

  • Prioritize systems based on their exposure to untrusted compressed data. Internet-facing applications that decompress Brotli request bodies and services that retrieve attacker-controlled content require immediate attention. Extend the review to background workers processing uploaded files, queue messages, cached data, and gateway components configured for Brotli decompression.

  • Preserve relevant security telemetry from previously exposed systems to support retrospective investigation. Review HTTP request metadata, application errors, process restarts, parent-child process activity, DNS requests, file operations, and outbound network connections. Correlate suspicious events using timestamps, process identifiers, and workload information to determine whether exploitation may have occurred.

Interim risk reduction when patching is delayed

  • Disable Brotli request-body decompression on endpoints that do not require it. Where disabling decompression is not feasible, consider rejecting Brotli-encoded requests at the application or gateway layer and verify that the change does not disrupt legitimate traffic. These measures reduce exposure through inbound requests but do not protect applications that decompress external responses.

  • Restrict outbound connections from services that retrieve remote content, particularly when users can influence destination URLs. Enforce approved destination lists and limit unnecessary network access. Where operationally possible, suspend workflows that require the affected runtime to decompress untrusted external responses until the patched version is deployed.

  • For applications processing compressed files, cached objects, or queue messages, temporarily quarantine untrusted inputs or suspend the affected processing functions. Resume normal processing after confirming that the vulnerable decoder has been replaced.

  • Apply least-privilege controls to affected workloads. Restrict unnecessary filesystem access, sensitive credentials, command interpreter execution, and outbound connectivity. These controls can limit the impact of successful exploitation, but they cannot prevent memory corruption within the vulnerable decoder.

  • Avoid relying solely on the Accept-Encoding: identity header or generic gateway filtering rules as a mitigation. Applications may still receive compressed responses, depending on how the remote endpoint and HTTP client handle content encoding. Verify the actual decompression behavior of the application and prioritize replacing the vulnerable decoder.

Conclusion:

Node2Shell is a memory-safety defect in a widely reused decoder, with credible laboratory code execution and evidence of active exploit traffic. Enterprise priority should follow reachable decompression paths and the privileges of the process performing them. Patch the deployed binary or bundled decoder, confirm the corrected build is running, and review relevant host and application telemetry for suspicious activity. The available evidence supports urgent action but not a claim of confirmed compromise or actor attribution for any specific organization.

References:

[1] Official Node.js security release — October 2026 security releases 

[2] NVD — CVE-2026-111497 analyzed record and API data 

[3] Google Brotli — upstream patch: Detect and report invalid stream earlier 

[4] Google Brotli — fixed release tags 

[5] Node.js — zlib and Brotli API documentation 

[6] Node.js / Undici — fetch response-decoding implementation 

[7] Express — version 5 migration and Brotli request-body parsing 

[8] body-parser — supported encodings and parser options 

[9] .NET — CVE-2026-111497 security advisory 

[10] Bun — bundled Brotli decoder security advisory 

[11] Istio — ISTIO-SECURITY-2026-007 

[12] Envoy — Brotli decompressor security advisory 

[13] Python advisory database — PYSEC-2026-4322 

[14] PyPI — Brotli and brotlicffi release information 

[15] Debian — DSA-6582-1 security update 

[16] ELLIO — Node2Shell public exploitation research and sensor observation 

[17] Imperva — controlled RCE demonstration and technical analysis 

[18] Sysdig — Node2Shell detection and exploitation-status update 

[19] Rapid7 — technical analysis and release guidance 

[20] Akamai — Inside Node2Shell technical analysis 

[21] Brotli4j — bundled native decoder security advisory 

[22] CISA — Known Exploited Vulnerabilities catalog search 

[23] Datadog Security Labs — reproducibility and observability analysis, 29 October 2026 

[24] Node.js GitHub issue #67075 — backported fix and reported Brotli version string, 28 October 2026