Node2Shell Brotli Flaw Triggers Patches Across Node.js, .NET and Python
Why a decoder bug crosses runtime boundaries
Node2Shell shows how a flaw in a shared compression decoder can cross runtime boundaries. The Brotli bug can corrupt memory when applications process attacker-controlled compressed data, opening potential paths to remote code execution, information disclosure or denial of service. The issue sits in a component that may be bundled into different runtimes and language packages, so a single flaw can surface in systems that otherwise look unrelated.
Tracked as CVE-2026-111497, the high-severity vulnerability was first identified in the Brotli decoder bundled with Node.js. Node.js disclosed it on October 21, 2026, and Microsoft followed with out-of-band .NET updates on October 25. Separate research found the same vulnerable decoder code in Python’s Brotli and brotlicffi packages; both have since been patched. The sequence is a reminder that fixing a runtime doesn’t necessarily fix every copy of the underlying library.
The practical exposure depends on whether an application feeds untrusted Brotli data into an affected decoder. Services that decompress untrusted HTTP responses or request bodies deserve particular attention, since the risky input can arrive through ordinary application traffic. Runtime and library copies baked into containers or deployed application artifacts also need to be accounted for. If you're working in this space, start by tracing where compressed data enters and which decoder actually processes it.
An invalid block switch corrupts decoder memory
Brotli is a lossless compression format used to shrink data exchanged between applications and servers. A decoder must interpret the compressed stream’s structure as it reconstructs the original data, and Node2Shell stems from its response to an invalid block-type transition. In a malformed stream, that transition can push the decoder into an error path that its fast processing route doesn’t handle safely.
The public proof of concept describes a failure in DecodeBlockTypeAndLength(): an invalid block switch can produce an ambiguous error value, which the decoder’s fast path doesn’t handle correctly. Processing then continues with an invalid internal state, allowing an out-of-bounds write to damage memory. The bug combines an unchecked return value (CWE-252) and an out-of-bounds write (CWE-787). That combination matters: the first mistake lets execution proceed after an error, and the second gives the bad state a way to alter memory.
Remote code execution has been demonstrated in a public GitHub lab and independently by cybersecurity firm Imperva, which named the issue Node2Shell. The PoC targets Node.js 24.22.0 on Linux x86-64 and depends on a particular binary and memory layout; execution is probabilistic and may require retries. That makes the demonstration a concrete warning, but not evidence that every affected application can be exploited in the same way. The same request fails against patched Node.js 24.22.1, whose decoder rejects the invalid transition.
OpenAI Codex Security researchers Khai Tran and Sylvie Mayer found the flaw during security testing and reported it to the Node.js project. The path from discovery to a fix also highlights the role of testing components that are often treated as plumbing. A decoder can sit far from an application’s headline features, yet still handle data supplied by an outside party.
Fixed releases span runtimes and dependencies
Node.js fixed the issue in versions 22.23.4, 24.22.1 and 26.12.1, according to its security release notice. Administrators should move to a fixed release or later update, rebuild affected container images and redeploy applications that bundle vulnerable runtimes. Updating a base image alone may not refresh an application artifact that already contains its own runtime. End-of-life Node.js versions should be treated as affected and migrated to supported releases.
Microsoft’s October 25 updates cover .NET 8, 9 and 10, plus .NET 11 Release Candidate 3. Fixed runtime versions are 8.0.33, 9.0.22 and 10.0.14; the preview line is fixed in 11.0.0-rc.3.26522.148. Updated SDKs are available too. Self-contained and Native AOT applications may need rebuilding and redeployment because an update to a shared runtime won’t replace a decoder already linked into an executable. Here's the thing: patch status depends on how the application was built, not just which runtime version an operator sees installed.
For Python, OpenSourceMalware identified Brotli 1.2.1 and brotlicffi 1.2.1.0 as fixed releases. They replace vulnerable versions up to 1.2.0 and 1.2.0.2, respectively. Google also published patched Brotli library versions, addressing the flaw in versions 1.0.10, 1.1.1 and 1.2.1. Teams should check direct dependencies and packaged copies, since an application can carry a decoder independently of the system runtime.
What the disclosure means for deployment teams
No exploitation in the wild had been publicly reported at publication, though proof-of-concept code had already been available for days. The immediate engineering task is to trace which deployed components decode untrusted Brotli data, then update and rebuild every affected artifact. This is more significant than it looks: a patched package in a development environment offers little protection if production still runs an older bundled copy.
That said, the public demonstration’s dependence on a particular binary and memory layout is relevant when assessing exposure. It describes one route to code execution under particular conditions, while the underlying memory corruption can still create other consequences, including denial of service or information disclosure. Security teams need both views: the demonstrated exploit helps explain impact, while the vulnerable input path determines whether a service is exposed.
(and this is the part most people overlook) Dependency inventories don’t always reveal how a deployed executable was assembled. A runtime update, package update and container rebuild can each address different copies of the decoder, so teams need to confirm the resulting artifacts actually contain fixed code. For operators, the practical work is exacting. But it’s also clear: identify the decoder, follow its build path, and verify the deployed version.
Then repeat that review wherever the same compression support is embedded. A shared library can turn a narrow coding error into a cross-runtime maintenance problem, and the fix only reaches systems whose owners know they’re carrying it. The patch exists; the remaining question is whether every relevant copy has been replaced.