It's been a busy week for supply chain incidents. Yesterday the PHP Foundation disclosed PHP2Shell, a vulnerability that has existed in PHP for over a decade. We broke down how that worked in our post from yesterday. Not to be outdone by its older brother, Node.js disclosed its own memory vulnerability today, which gets the same 2Shell postfix. This affects a number of third-party packages including the popular Express.js framework
The name “Node2Shell” is somewhat misleading. The vulnerability is in Node’s Brotli decoder, but like many vulnerabilities, exploitation depends on how an application reaches that code. Node’s built-in fetch() creates an exposure path only when an application retrieves an attacker-controlled or attacker-influenced response, so it does not affect every Node service equally. For example: Express 5 applications using the body-parser middleware (2.x) with inflation enabled may pass Brotli-encoded request bodies to the decoder before JSON parsing. When that middleware is mounted globally, many public body-bearing routes may be reachable, subject to the required content-encoding and parser conditions.
These factors all make the vulnerability dangerous even though it is not universally exploitable. Applications running affected Node versions should upgrade to the patched releases as soon as possible; see the Node.js security advisory.
Where the vulnerability lives
Brotli is a lossless compression format widely used on the web. The br in Accept-Encoding: br, gzip refers to Brotli. Node.js supports Brotli through its built-in zlib module, which includes a native decoder. The issue is an improper bounds check in the reference implementation of Brotli leading to a buffer overflow (out-of-bounds write). The authors of the Brotli RFC (7932) sagely noted that buffer overflows may result in command execution - a common problem with decompression and not unique to Brotli.
The vulnerability is in that decoder, which is bundled into the Node.js runtime. It is not a vulnerability in an npm package called brotli, and it is not a bug in body-parser itself. But this is important because body-parser and others pass attacker-controlled compressed data to the vulnerable Node decoder.
This also means that Node and Express will not be the only affected packages, runtimes or frameworks and anything that bundles the same Brotli implementation may be vulnerable under certain conditions.
How applications reach the vulnerable code
For inbound requests, the header Content-Encoding: br allows Express 5 applications using body-parser 2.x automatically decompress Brotli-encoded request bodies when inflation is enabled. A malformed request can reach Node’s Brotli decoder before the application attempts to parse the JSON. But this doesn’t make every Express application automatically vulnerable. The application must be running an affected Node version, use a Brotli-capable parser, have inflation enabled, and expose a route where that parser is mounted. Which is a tricky set of prerequisites and even older Express 4 applications do not have the same default Brotli request path.
The same decoder can also be reached through Node’s built-in fetch() when an application retrieves an attacker-controlled or attacker-influenced Brotli-encoded response.
What the fix changed
The underlying bug was an error-handling problem in the Brotli decoder. It could confuse incomplete input with invalid input and continue processing a malformed stream instead of rejecting it. The upstream Brotli fix introduced separate error states and made the decoder stop immediately when it detected an invalid block transition.
The upstream project disclosed the issue in the Brotli 1.2.1 changelog, which lists CVE-2026-111497 as an out-of-bounds write that could permit remote code execution. Node.js released patched versions 22.23.4, 24.22.1, and 26.12.1 in its security advisory.
Known Packages for Node2Shell
The following confirmed entry points are included for now. This list is not exhaustive; we will add additional packages and frameworks as their exposure is verified.
Integration | Representative code | Exposure path |
app.use(express.json()) | Brotli-encoded request bodies can reach Node’s decoder when inflation is enabled. | |
const response = await fetch(url) | Brotli-encoded responses may be automatically decompressed when the URL or upstream response is attacker-controlled. | |
Direct node:zlib usage | createBrotliDecompress() | Applications are exposed when this API receives attacker-controlled compressed data. |
app.use(bodyParser()) | Brotli-encoded request bodies are passed by co-body to inflation, which pipes them through Node’s Brotli decoder. Also covers @koa/bodyparser, koa-body, @feathersjs/koa, koa-json-body, Egg and Strapi; @adonisjs/bodyparser calls inflation directly. | |
Fastify / @fastify/compress | await app.register(require('@fastify/compress')) | Registering the plugin adds request decompression, so Brotli-encoded request bodies are decoded before Fastify’s content-type parsers run. |
app.use(express.json()) | Brotli-encoded request bodies are decoded synchronously through fast-zlib inside the uWS data callback. |
This has been a busy week for vulnerability disclosures
With PHP2Shell and Node2Shell appearing within a day of each other, it is tempting to think security has suddenly gotten worse. The larger trend, however, has been building for years. Mandiant measured the average time to exploitation falling from 63 days in 2018–2019 to 32 days in 2021–2022, while Rapid7’s Q3 2026 data puts recent high-severity exploitation at roughly three days. A separate Nucleus analysis found a median of 5.5 days from public proof of concept to CISA KEV listing. The metrics differ, but the direction is clear. Defenders increasingly have days, not months, to respond.
AI is accelerating a trend that was already underway and expanding who can work at the lowest levels of the software stack. PHP2Shell and Node2Shell are not obscure npm bugs. They affect runtimes and native libraries written in C and C++, components that sit beneath much of the web. Finding and weaponizing flaws there once required a small group of specialists. AI tools can now help researchers and attackers analyze years of patches, search for related bugs, fuzz exposed interfaces, and test whether old fixes fully closed the underlying issue.
Open source makes this activity easier to see because the code, patches, and disclosures are public. The same capabilities also apply to proprietary software, APIs, and compiled applications. The difference is that when an internal service is attacked, there may be no public changelog and no obvious SOC alert to explain what happened.