Guide

Node2Shell: the Node.js Brotli flaw, who is exposed and how to patch it

Node2Shell is the name researchers gave CVE-2026-111497, a flaw in the Brotli decoder that ships inside Node.js. On 21 October 2026 the Node.js project fixed it in 22.23.4, 24.22.1 and 26.12.1. An app that decompresses Brotli data someone else can supply, such as a compressed request body or a response fetched from another server, can crash, leak memory or run an attacker's code. The fix is in Node.js itself, so `npm update` doesn't apply it: the runtime has to be upgraded everywhere it runs.

What Node2Shell is

Brotli is a compression format that web servers and browsers use alongside gzip. Node.js bundles a Brotli decoder in `node:zlib`. The Node.js advisory describes the bug: an invalid block switch in a compressed stream was treated as a temporary need for more input instead of a format error, so the decoder kept appending bytes to an eight-byte internal buffer and wrote past its end. Memory corruption like that can crash the process, leak memory, or let an attacker run code.

Node.js rates it high and says it permits remote code execution. It was reported by OpenAI Codex Security. Imperva's researchers then reproduced it as code execution without authentication, and proof-of-concept code is public, so treat every unpatched Node.js service that handles outside data as a target.

Are you exposed?

A Node.js process is exposed when it, or a library it uses, decompresses Brotli data that an attacker controls. Imperva tested two common ways that happens.

**Incoming requests.** Express 5 and body-parser 2 decompress request bodies sent with `Content-Encoding: br`, because body-parser's `inflate` option is on by default. So an app with `app.use(express.json())` can be reached by a single crafted request, before any login.

**Outgoing requests.** Node's built-in `fetch()` asks for and decompresses Brotli responses on its own. Any server your code calls that an attacker controls or has compromised can reach the decoder: webhooks you call back, link previews, scrapers, AI agents that fetch the pages a user gives them, health checks of other sites.

Code that calls the Brotli functions in `node:zlib` directly on outside data is exposed the same way. Firewalls in front of your app only see the first path: they can't inspect what your code fetches from elsewhere.

Which versions fix it

Each supported Node.js line has one release with the fix (the table below). The same release also fixes nine other vulnerabilities, including three TLS certificate and DNS bugs rated high, so it's worth taking even if your app never touches Brotli.

Node.js 20 and older get no fix: they're past end of life, and the Node.js project says end-of-life versions are always affected when a security release ships. Bun, which bundles its own Brotli decoder, fixed the same flaw in 1.4.4.

Where Node.js hides

The upgrade has to reach every copy of Node that runs your code, and there are usually more than one.

**Container images.** A Dockerfile pinned to an exact version, such as `node:24.22.0`, stays vulnerable however often you rebuild it: move the pin to 24.22.1 or later. Base images that bundle their own Node (browser-testing images, for example) pin whatever was current when they were built, so upgrade Node inside them too.

**Servers and CI.** Node installed with nvm, a package manager or a CI setup action is upgraded there, then the service restarted.

**Hosting platforms.** Vercel deployed firewall rules against the incoming path for every project on 21 October and manages patch versions for its Node.js 22.x and 24.x runtimes, so those projects need no version change. Projects still on Node.js 20 must switch to 22.x or 24.x and redeploy. Vercel also notes its firewall doesn't cover responses your functions fetch from other servers. On other hosts, check the platform's own notice for which Node version your functions run.

**Apps built with AI.** If an AI app builder or coding agent wrote your app's server code, the question is the same: which runtime runs it, and at which version. See monitoring for AI-built apps for what else to watch once it's live.

How to check

Run `node --version` on laptops, CI runners and servers, and `docker run --rm <image> node --version` for each container image. In a running service you can log `process.version` at startup. Anything below the fixed release for its line, or on Node.js 20 or older, needs upgrading.

If you can't update today

Upgrading is the fix. Until it's rolled out, you can narrow the incoming path: refuse requests with `Content-Encoding: br` at your proxy or firewall, or set `inflate: false` on body-parser and `express.json()`, which rejects every compressed request body (check first that none of your clients send them).

There's no setting that protects the outgoing path, because a malicious server can send a Brotli response whatever your code asks for. Avoid fetching untrusted URLs from unpatched services until they're upgraded.

How Relvato helps

Relvato can't read the Node.js version of a site from outside, and it won't send attack-shaped requests to find out, so it doesn't flag Node2Shell directly.

What it does: the exposure scan flags an `X-Powered-By: Express` header, which tells every scanner what your stack is (`app.disable("x-powered-by")` removes it). And upgrading Node is a change like any other: with deploy checks from GitHub, Relvato re-runs your monitors after the deploy, so you know sign-in, checkout and your key pages still work on the new runtime.

Relvato runs on Node.js too. Its monitors fetch pages from the sites they watch, so we moved them to Node 24.22.1 the week the fix shipped.

Runtimes with the Node2Shell fix

RuntimeFixed inNote
Node.js 2626.12.1Current release line
Node.js 2424.22.1LTS
Node.js 2222.23.4LTS
Node.js 20 and olderNo fixEnd of life: upgrade to 22 or 24
Bun1.4.4Bundles its own Brotli decoder

Questions, answered

Does npm update fix Node2Shell?

No. The flaw is in Node.js itself, not in a package, so updating dependencies doesn't change it. Upgrade the Node.js runtime to 22.23.4, 24.22.1 or 26.12.1 or newer wherever your code runs, then restart or redeploy.

I don't use Express. Am I safe?

Not necessarily. Node's built-in fetch() decompresses Brotli responses by default, so code that fetches from servers you don't control is exposed whatever framework you use. Upgrade Node anyway.

My app is on Vercel. Do I need to do anything?

On Node.js 22.x or 24.x, Vercel manages the patch version and has firewall rules against malicious request bodies, so no version change is needed. On Node.js 20, switch to 22.x or 24.x and redeploy. Vercel's firewall doesn't cover responses your functions fetch from other servers.

I'm on Node.js 20 or 18. What now?

They get no fix: both are past end of life. Upgrade to Node.js 22 or 24, test, and redeploy.

Does a web application firewall protect me?

Only against crafted requests coming in. It can't see the responses your code fetches from other servers, which is the other way in. Rules buy time; the upgrade is the fix.

Sources

Related reading
Guide

Know your app still works after every update.

Relvato re-runs your monitors after each deploy and update, from sign-in to checkout, so a runtime upgrade that breaks something shows up before your users find it.