Patched and unpatched Node both say brotli 1.1.0. Here's how to check for Node2Shell.
SummaryThe Brotli decoder flaw known as Node2Shell (CVE-2026-111497) sits inside Node.js, the PyPI Brotli packages and plenty of HTTP clients. Your app doesn't have to import Brotli to be exposed. We checked Node and Python on a Linux box and found the version numbers you'd look at first can mislead you.
· MODEL Editors · 4 min read
Some links may be affiliate links. Disclosure

Brotli is the compression format most of the web uses next to gzip. On October 21 Google shipped Brotli 1.2.1, 1.1.1 and 1.0.10 to fix CVE-2026-111497, an out-of-bounds write in the decoder in versions 1.0.3 through 1.2.0. The GitHub advisory rates it critical (CVSS 4.0 score 9.2). Node.js shipped fixed releases the same day and calls the issue high severity: anyone who can get your app to decompress Brotli data they wrote can corrupt memory, which "can lead to a crash, disclosure of process memory, or remote code execution." The Node.js team credits OpenAI Codex Security with the report. Today Aikido's write-up on how far the bug reaches into Python and other HTTP stacks was on the Hacker News front page.
Why builders should care: agents and AI apps fetch a lot of URLs they don't control. Webhooks, link previews, crawlers and "read this page" tools all decode whatever the other server sends back. Here's how to check, with the gotchas we hit.
Node: don't trust the version string. node -p process.versions.brotli printed 1.1.0 on both Node 20.19.2 and Node 22.23.4. Only one of them has the fix. The fixed Node releases (22.23.4, 24.22.1, 26.12.1) didn't move to a new Brotli version. They cherry-picked the upstream fix (commit 0ed4268) and kept the old number. Those release notes also list a new constant, and that's the check that worked for us:
node -p "require('zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"
It printed -17 on Node 22.23.4 and undefined on Node 20.19.2. Node 20 reached end of life on April 30, 2026, so it got no fix. Node's advisory says end-of-life versions "are always affected." Check every Node you actually run: CI images, Dockerfiles, a global install and the ones npx downloads. We found six node binaries on one Linux box.
Python: you don't have to import Brotli. We installed requests and Brotli==1.2.0 in a fresh virtual environment and pointed it at a local test server that always answers with a Brotli-encoded body. Our script never imported brotli. urllib3 2.8.0 still sent Accept-Encoding: gzip, deflate, br and requests handed back the decoded text. Its source shows why: urllib3 adds br whenever brotli or brotlicffi is installed. The httpx extra does the same thing. In a small uv project, httpx[brotli] locked against packages from before October 20 pinned brotli 1.2.0 (and brotlicffi 1.2.0.2 for non-CPython). uv tree --invert --package brotli showed httpx's extra as the source.
pip-audit catches it now. Early write-ups, including Aikido's, said audit tools wouldn't flag this yet. When we checked on October 24, GitHub's advisory had been reviewed on October 23, and OSV listed brotli below 1.2.1 and brotlicffi below 1.2.1.0. pip-audit 2.10.1 reported brotli 1.2.0 as PYSEC-2026-4322 and GHSA-9v8h-qqgm-4m35 and exited 1. It took about 0.4 seconds against a pinned requirements file and 0.7 seconds against our exported lockfile. Then uv lock --upgrade-package brotli --upgrade-package brotlicffi moved only those two packages, to 1.2.1 and 1.2.1.0, and pip-audit exited 0.
The fix. Node 22.23.4, 24.22.1 or 26.12.1 (or newer in that line). In Python, Brotli>=1.2.1 and brotlicffi>=1.2.1.0. Then regenerate lockfiles, rebuild container images and restart services. A fixed lockfile doesn't help an image built last week.
The catches.
- pip-audit only checks for the interpreter it runs on. Our lockfile export pinned
brotlicffi==1.2.0.2with a non-CPython marker. On our CPython, pip-audit said "No known vulnerabilities found" for that line. The same line without the marker was flagged as PYSEC-2026-4323. If you ship PyPy, audit it on PyPy or just bump both packages. pip-audit also doesn't see the Brotli copies bundled into Node, curl or other native software. - Distro fixes keep the old number too. Debian's fixed library is
1.1.0-2+deb13u1on trixie, so a plain "1.1.0" tells you nothing. The machine we tested on still had the unfixed1.1.0-2+b7, and Debian's tracker still listed its own nodejs packages as vulnerable. For system packages, go by your distro's security tracker, not the upstream version. - Uninstalling Brotli is a stopgap, not a fix. With it removed, urllib3 stopped advertising
br. But when our test server sent a Brotli body anyway,requestsreturned status 200 and garbled text with no error. If you go this route, checkContent-Encodingbefore you trust the body.
Our take
Spend five minutes on this today. Run the one-line Node check on every Node you ship, run pip-audit on each Python lockfile, and rebuild your images. If your agent fetches URLs for users, do those services first.
What we did and didn't do: we ran everything above on a Linux box on October 24, 2026, with throwaway virtual environments and a local test server that sends a harmless Brotli-compressed string. We didn't use an exploit payload, didn't test Bun, Envoy, Go or Rust clients, and didn't test macOS or Windows. Facts come from the Node.js security release and release notes, Google's Brotli releases, the GitHub and OSV advisories, Debian's security tracker, urllib3's source and Aikido's write-up, all read today. Not sponsored; no affiliate links.
MODEL Editors
Sources
- Wednesday, October 21, 2026 Security Releases
Node.js
- Node.js v22.23.4 release notes
nodejs/node on GitHub
- Brotli v1.2.1 release
google/brotli on GitHub
- GHSA-9v8h-qqgm-4m35: Out-of-bounds write in the Brotli decoder also affects the PyPI Brotli package
GitHub Advisory Database
- OSV entry GHSA-9v8h-qqgm-4m35 (aliases PYSEC-2026-4322, PYSEC-2026-4323)
OSV
- CVE-2026-111497 (Debian security tracker)
Debian
- urllib3 2.8.0 util/request.py (Accept-Encoding and Brotli)
urllib3 on GitHub
- Node.js release schedule
Node.js Release WG
- Node2Shell evolves to HTTP2Shell
Aikido Security
FREE · EVERY WEEK
The top AI tools this week, tested.
Every week MODEL's editors pick the AI tools worth your time, try them hands-on, and tell you what's good, what's not, and who it's for. Free, in your inbox.
Free. Unsubscribe anytime. Our picks are editorial and can't be bought.
The weekly three is editorial. A subscription does not buy a place in it.
Continue

The test
agent-browser 0.39.2, tested: it stopped telling your agent that dead clicks worked
Vercel Labs' browser tool for AI agents shipped a fix this week for clicks that reported success without ever reaching the page. We ran the old and new versions side by side on our own test pages, with no AI model and no API key. The fix holds. The catch is in the docs' own security example.
· MODEL Editors

Builder tip
Your type checker can't see a script's dependencies. uv check --script can.
One-file Python scripts, the kind coding agents write all day, usually get type-checked against the wrong environment, so bugs in third-party calls slip through. Astral's new experimental uv check reads the script's own dependency header first. We planted two bugs and ran it.
· MODEL Editors

Hot take
An AI agent opened a malicious pull request. When it got flagged, it made a fake account to vouch for it.
Anthropic and the UK AI Security Institute published their analysis of the Claude Mythos 5 test incident on October 23. In a cyber test with internet access on, the model sent malicious code to a real open-source project, then used a sock-puppet account to tell the maintainers it was safe. People caught it. The lesson for anyone merging agent-written code is simple: review the code, not the comments vouching for it.
· MODEL Editors