

Stopping Node2Shell: How SentinelOne Protects Customers From Brotli-Based Remote Code Execution
Executive Summary
On October 21, 2026, the Node.js project released security updates that fix CVE-2026-111497, an out-of-bounds write in the Brotli decoder bundled with the runtime. Vendors have labeled the vulnerability Node2Shell, Brotli2Shell, Broccoli2Shell, and HTTP2Shell, because the flaw sits in Google's Brotli library and reaches software well beyond Node.js. Any application that decompresses attacker-controlled data with a vulnerable Brotli library could be at risk. Google, as the CVE Numbering Authority, scored it 9.2 under CVSS v4.0, and Node.js rates it high.
CISA added CVE-2026-111497 to its Known Exploited Vulnerabilities (KEV) catalog on October 27, 2026, with a November 10, 2026 deadline for federal civilian agencies. The public telemetry we reviewed shows exploitation attempts against honeypot sensors, and researchers have demonstrated code execution in lab environments. As of October 29, 2026, we are not aware of a public report of a confirmed compromise of a production system.
This report details Node2Shell's mechanism, affected versions, and observed activity, and outlines how SentinelOne customers and partners can strengthen their defenses.
Key Highlights
One flaw, many patches. Node.js, Google Brotli, Bun, .NET, Python, Envoy, Istio, and PHP for Windows each shipped their own fix. Updating one does not update the others.
Attempts are confirmed. Production compromise is not. ELLIO and Previdian have each recorded an exploitation attempt against their honeypot sensors. Previdian notes that such observations do not show the target was vulnerable or that the attempt succeeded.
A default Node.js server is not exposed by itself. Something must hand attacker-controlled Brotli data to the decoder. Node.js names direct node:zlib use. Express 5 request bodies and built-in fetch() responses reach the same decoder, and Imperva reproduced both in the lab.
A failed exploit still costs you. The Node.js advisory lists a crash as an outcome, and Sysdig reports that crashes have been easy to reproduce. Repeated crashes are a denial of service against any service that decodes attacker-influenced Brotli.
The fix was visible for nearly eight months before release. Google committed it on February 27, 2026, with no release and no advisory. End-of-life Node.js 20, 23, and 25 are not expected to receive a fix.
Organizations should take the following steps immediately:
Upgrade Node.js to 22.23.4, 24.22.1, or 26.12.1, then restart processes and rebuild container images.
Inventory every other runtime and library that embeds the Brotli decoder, and patch internet-facing services first.
Where patching must wait, reject inbound requests that carry Content-Encoding: br at the proxy or load balancer.
What is Node2Shell
Node2Shell is a memory corruption flaw in the Brotli decoder, the code that expands Brotli-compressed data. A Brotli stream signals switches between block types. When a stream declares only one block type, a switch is invalid and the decoder should reject it. The vulnerable decoder instead reported the invalid switch as a request for more input. The caller supplied more bytes, and the decoder kept appending them to an eight-byte internal buffer and wrote past its end, according to the Node.js advisory.
Node.js lists the outcomes as a crash, disclosure of process memory, or remote code execution, and the CVE record describes the attacker as unauthenticated. Imperva demonstrated code execution on the official Node.js 24.22.0 arm64 image. Microsoft describes the .NET impact as information disclosure, denial of service, or elevation of privilege.
Node2Shell at a Glance
Attribute | Detail |
|---|---|
CVE | CVE-2026-111497, also called Brotli2Shell, Broccoli2Shell, and HTTP2Shell |
Weakness | Unchecked return value (CWE-252) leading to an out-of-bounds write (CWE-787). No authentication required. |
Severity | CVSS v4.0 9.2 (Google, CNA). Node.js: high. |
Affected Component | Google Brotli 1.0.3 through 1.0.9, 1.1.0, and 1.2.0, bundled or linked by many products |
How Attacker-Controlled Brotli Reaches the Decoder
Path | Condition |
|---|---|
Inbound request bodies | Routes that use express.json(), express.urlencoded(), express.text(), or express.raw() in Express 5 or body-parser 2 decompress bodies sent with Content-Encoding: br by default. Any client can send one. |
Outbound responses | Built-in fetch() decodes Brotli automatically, so a malicious or compromised server can target the client. |
Direct calls | Applications that pass untrusted input to zlib.brotliDecompress() or zlib.createBrotliDecompress(). |
Disclosure Timeline
Date (2026) | Event |
|---|---|
February 27 | Google commits the upstream fix with no release and no advisory. |
October 21 | Node.js discloses CVE-2026-111497. Google releases Brotli 1.0.10, 1.1.1, and 1.2.1. |
October 22 | Imperva demonstrates code execution on arm64. CVE record is published. |
October 25 | Microsoft releases out-of-band .NET security updates. |
October 27 | CISA adds the CVE to the KEV catalog. |
Exploitation in the Wild
Exploitation attempts have been recorded, but a successful attack on a production system has not been publicly reported as of October 29, 2026. CISA added CVE-2026-111497 to its KEV catalog on October 27, 2026, with a November 10, 2026 deadline for federal civilian agencies under BOD 26-04.
The public telemetry comes from honeypots. Two threat intelligence providers each recorded an attempt: ELLIO saw a request built for Node.js 24.22.0 on x86-64 on October 26, and Previdian saw one from a U.S.-based address on October 27. Previdian notes that such observations do not show the target was vulnerable or that the attempt succeeded.
Researchers have reproduced code execution only in lab testing. Imperva ran code on the official Node.js 24.22.0 arm64 image through fetch() and Express 5 request bodies, needed multiple attempts, and did not test every Node.js build. Public proof-of-concept code appeared within hours of the October 21 release, according to Sysdig, so organizations should expect further attempts, particularly against internet-facing Express 5 services.
Observed Indicators
Type | Indicator |
|---|---|
IP Address | 94[.]154[.]43[.]7 |
SHA-256 | 7fcbdaaecd4419e2930927844f3b772668204737a4e7602a2290c991c93c5c4b |
Behavior | A Node.js process that starts or becomes a shell |
Patch Status
Node.js has fixed every supported release line: 22.x, 24.x, and 26.x. It will not patch end-of-life lines, which the project says are always affected when a security release occurs. Organizations running Node.js 20, 23, or 25 have no patch to apply and must upgrade to a supported line.
Product | Affected Version | Fixed Version |
|---|---|---|
Node.js | 22.x before 22.23.4, 24.x before 24.22.1, 26.x before 26.12.1 | 22.23.4, 24.22.1, 26.12.1 |
Node.js 20, 23, 25 | All versions | No fix. Move to a supported line |
Google Brotli | 1.0.3 through 1.0.9, 1.1.0, 1.2.0 | 1.0.10, 1.1.1, 1.2.1 |
Bun | 1.0.21 through 1.4.3 | 1.4.4 |
Microsoft .NET | 8 before 8.0.33, 9 before 9.0.22, 10 before 10.0.14, 11 before RC3. Exposed only where Brotli decompression is in use. .NET Framework is not affected. | 8.0.33, 9.0.22, 10.0.14, 11 RC3 |
PHP for Windows | Builds that bundle Brotli 1.0.3 through 1.2.0 | 8.2.35-1, 8.3.36-1, 8.4.27-1, 8.5.12-1 |
Python Brotli, brotlicffi | Bundled Brotli 1.0.3 through 1.2.0 (brotlicffi up to 1.2.0.2) | Brotli 1.2.1, brotlicffi 1.2.1.0 |
Envoy Proxy | 1.36.11, 1.37.7, 1.38.5, and 1.39.2 | 1.36.12, 1.37.8, 1.38.6, 1.39.3, 1.40.0 |
Istio | 1.29.x before 1.29.9, 1.30.x before 1.30.6, 1.31.x before 1.31.2 | 1.29.9, 1.30.6, 1.31.2 |
Recommended Mitigations
Patch, Restart, and Rebuild
- Upgrade to a fixed Node.js release, update every Dockerfile that pins an older tag, and restart or redeploy every workload.
- Confirm patch status from the Node.js release version running in each workload, not a bundled library version string, which may not reflect a backported fix.
Find Every Copy of the Decoder
- Inventory Bun, .NET, Python Brotli, Envoy, Istio, PHP for Windows, and statically built executables, including staging, CI, build images, and developer machines.
- Where Node.js links the system Brotli library, as it does on Debian, check your distribution’s advisory for the Node.js package as well as brotli. Debian’s tracker lists both.
- PHP for Windows fixed the flaw with rebuilt packages that keep the same PHP version number, so php -v looks the same before and after. Check the -1 build suffix or the SHA-256 on the download page.
- Move off Node.js 20, 23, and 25 on a defined date.
Reduce Exposure Until Patching Finishes
- Reject requests with Content-Encoding: br at the WAF or proxy, or set the body-parser inflate option to false so compressed bodies return HTTP 415. The second option also rejects gzip and deflate bodies, so test client traffic first.
- Restrict server-side fetches to trusted destinations. Link previews, webhooks, and crawlers send attacker-influenced URLs into fetch(), and removing br from Accept-Encoding does not stop a hostile server from replying with Brotli.
- Enable a vendor WAF rule as a stopgap where one exists. It does not replace the upgrade.
Limit the Blast Radius
Run Node.js services as a non-root user and limit outbound connections from Node.js hosts. Docker runs containers as root by default, and the official node image provides a node user (uid 1000) that you must select with USER or -u.
Watch for Failed Attempts
Alert on repeated worker crashes after requests with Content-Encoding: br. Where core dumps are enabled, restrict who can read them and shorten retention, because a core file can hold memory contents from other users’ sessions.
How SentinelOne Protects You
Node2Shell exploits the Brotli decoder inside the Node.js process. Patching Node.js and every other copy of the Brotli decoder remains the primary control. SentinelOne provides detection and visibility into post-exploitation behavior while that work is underway.
The Singularity agent builds a storyline of process activity on a host, including the Node.js services targeted by Node2Shell. These processes have a predictable life: they answer requests, call APIs, and read files. They do not normally start /bin/sh, run reconnaissance commands, download executables into /tmp, or open connections to arbitrary hosts. Behavioral detection looks for that deviation from normal behavior.
Detection in Singularity AI SIEM
Platform detection content looks at what happens on the host after exploitation, not at the request body.
Attacker Step | Telemetry | Visible Indicators |
|---|---|---|
Code execution in the service | Process creation | Shell processes whose lineage or prior image is node, nodejs, or bun, including an in-place exec, followed by enumeration utilities (id, whoami, uname, hostname) or sensitive file reads |
Tooling download | Process creation, File creation | Downloaders (curl, wget, interpreters) fetching to world-writable paths, and executables written and then run from /tmp |
Files written by the service | File creation | A Node.js service account writing new executables or scripts outside its normal application paths |
Shell and C2 | Process creation, IP Connect | Shell processes with a socket as standard input or output, socket-redirection patterns (/dev/tcp, nc, socat), and unexpected outbound connections from Node.js service accounts |
Novel child process | First-seen analytics | A Node.js process that starts or becomes a shell or image it has never run in that environment |
Correlation rules tie these together. A request to the service, or an outbound fetch to an untrusted host, followed by a process spawn or file drop from the same Node.js process is the shape of a successful chain.
Visibility at the Edge
Sysdig reports that the crash is easy to reproduce, which makes repeated worker crashes and restarts a useful early signal. Web server, WAF, and CDN logs may show requests with Content-Encoding: br followed by bursts of HTTP 5xx responses and unexplained worker restarts. Singularity AI SIEM can ingest those sources alongside endpoint data if you forward them.
Hunt with Purple AI While You Patch
Patching is the only complete fix. While that work runs, analysts can ask Purple AI questions such as:
- Show me shell processes whose parent or prior image was node, nodejs, or bun since October 21.
- Show me new executable files written by the Node.js service account since October 21.
- Show me outbound connections from the Node.js service account to destinations we have never seen.
- Show me hosts with a spike in 500 responses followed by a Node.js process restart.
The last question depends on web server logs being ingested.
Confirm Agent Saturation on Node.js Hosts
Confirm the agent is deployed, healthy, and in protect mode on every server and container host that runs Node.js, Bun, or another service that decompresses Brotli. Start with internet-facing Express 5 services and services that fetch external URLs.
Disclaimer
Information contained herein is current as of October 29, 2026, and is subject to change as patch releases and threat activity evolve. Recipients should not rely solely on this report for security decisions and should consult with their security teams and SentinelOne account representatives for current guidance.



