Patching Node for the October 2026 security release
Node's 21 October release fixes ten CVEs across 22, 24 and 26, four rated high, and the Brotli decoder one is the one I'd patch first.

Yesterday was busy. PHP shipped fixes for two critical bugs, and a few hours later Node.js put out its own security release. The PHP one got the headlines, but nearly everything I run is Node, so this is the one I actually had to do something about.
The official post lists the patched versions as v26.12.1, v24.22.1 and v22.23.4.
| CVE | Severity | Lines | What it is |
|---|---|---|---|
| CVE-2026-111497 | High | 22, 24, 26 | Brotli decoder out-of-bounds write, can lead to remote code execution |
| CVE-2026-105483 | High | 24, 26 | TLS certificate hostname bypass when an IP is written in fullwidth digits |
| CVE-2026-106069 | High | 22, 24, 26 | TLS certificate hostname bypass when the host loosely resolves to an IP |
| CVE-2026-105482 | High | 22, 24, 26 | dns.resolve truncates names containing a NUL character |
| CVE-2026-105481 | Medium | 22, 24, 26 | Keep-alive socket processes a response that was written before the request was sent |
| CVE-2026-106072 | Medium | 22, 24, 26 | Non-canonical IPv4 hostnames let DNS SANs authenticate IP endpoints |
| CVE-2026-106074 | Medium | 22, 24, 26 | crypto.randomUUID() and randomInt() entropy caches saved into startup snapshots and SEAs |
| CVE-2026-106070 | Low | 26 | ZipFile returns attacker-controlled prefix bytes after failed header validation |
| CVE-2026-106071 | Low | 26 | Permission Model filesystem over-grant via wildcard lookup |
| CVE-2026-106073 | Low | 22, 24, 26 | Permission Model bypass with fs.realpathSync |
Dependencies were bumped as well: c-ares, OpenSSL (on 24 and 22), SQLite (on 22), Undici, and the bundled CA certificates, which now account for the eMudhra intermediate CA compromise.
The advisory only describes the Brotli bug in any detail. For the others I'm going from the titles and what I know about how those parts of Node get used, so read the rest as one working developer's interpretation rather than the official analysis.
The Brotli one
CVE-2026-111497 is an out-of-bounds write in the Brotli decoder, and the advisory says it can allow remote code execution. A decompressor that can be talked into writing somewhere it shouldn't is about as classic as memory bugs get.
So the question for your app is where Node decompresses Brotli data that you didn't create, and I think it's more places than most people would guess. fetch() in Node is Undici, which transparently decompresses a content-encoding: br response, so any server-side fetch to a URL you don't control is in scope: link previews, webhooks that call back out, scrapers, RSS readers. My AI Radar workflow pulls from a dozen or so feeds every hour, and I'd be surprised if none of them served Brotli. Then there's anything that accepts compressed uploads or request bodies and passes them to zlib.brotliDecompress. If you only ever decompress your own assets the risk is lower, but "we only fetch from places we trust" has a way of stopping being true without anyone noticing.
The two TLS hostname bypasses matter too. The hostname check is the part of TLS that makes sure a certificate belongs to the host you meant to talk to, and without it you still get encryption, just possibly to the wrong party. The fullwidth digits one looks like a normalisation problem. Unicode has a second set of digits, 0123, which look like ordinary digits but aren't the same characters, and if one layer treats 127.0.0.1 as a plain string while another converts it to 127.0.0.1, they can disagree about which host you're talking to. The medium one about non-canonical IPv4 addresses (octal, hex, fewer dots) seems to be the same family. And dns.resolve cutting names off at a NUL means good.example\0.evil.example could resolve as something other than what your code checked, which is exactly the pattern in an SSRF allowlist sitting in front of a fetch.
The snapshot one is subtle, and I found it the most interesting of the lot. Node keeps a small cache of random bytes so crypto.randomUUID() and randomInt() are quick, and if you build a user-land startup snapshot or a single executable application, that cache was being saved into it, so every process started from the same snapshot begins by handing out the same values. If you don't use snapshots or SEAs it doesn't affect you. If you do, and you use randomUUID() for anything that needs to be unguessable, patch that one quickly.
The low ones are mostly Permission Model bypasses, and this is the second release this year with path-matching issues there (July had CVE-2026-58043). I'd treat --permission as an extra layer and keep relying on containers and OS limits for the real isolation.
What I did
First I checked what was actually running, on the Mac, in CI and in the containers at home:
node -v
ssh kishan-server 'for c in $(docker ps -q); do
printf "%s " "$(docker inspect -f "{{.Name}}" $c)"
docker exec $c node -v 2>/dev/null || echo "-"
done'
Most of my Next.js apps run on a node:22-alpine image, and the official images had new tags within a few hours, so the fix was a rebuild that pulls the fresh base:
docker build --pull --no-cache -t seensooner-web:latest .
--pull is the bit that matters. Without it Docker reuses the node:22-alpine it already has, you redeploy, everything looks fine, and you're still on the old Node. I've been caught by that before. After the rebuild I ran node -v inside each container again to make sure it said v22.23.4, then bumped .nvmrc and the node-version in GitHub Actions. (If CI uses lts/* you'll get it automatically, but I prefer exact versions.)
Node 26 moves to LTS this month, 24 is active LTS and 22 is in maintenance, so it still gets security fixes. I'm staying on 22 for this one because it's a patch bump, and I'll move the apps to 24 in November once I've had time to test, rather than doing a major upgrade and a security patch on the same evening. If you're on 20 or older you aren't getting any of these fixes, and that's a bigger job than a rebuild.
First published on my blog. Cover photo: Victorgrigas, CC BY-SA 3.0, via Wikimedia Commons (source).
About the author
- Full stack engineer in London with 5+ years on production web platforms. I lead AI-assisted modernisation at Xanda: React and Go for the UK energy market, a government claims portal, and moving old Java and C++ systems onto the cloud. Outside work I run a small home server behind a Cloudflare Tunnel with a handful of public tools on it: Doorstep (rental alerts across Rightmove, OnTheMarket and OpenRent), SeenSooner (NHS A&E and planned-care waits), GridPulse (live GB grid carbon), Sift (LLM ticket triage that survives model failures) and AI Radar (a news digest written hourly by an n8n workflow). I write here about React and Next.js upgrades, Node, coding with AI agents, and the CVEs I've had to patch. Originals live at blogs.kishankanejiiya.tech.
Comments
Join the discussionNo comments yet. Be the first to comment.



