Security advisory · Published 23 October 2026 · By Prasad C G
On 21 October 2026 the Node.js project shipped security releases for every supported line. The most serious fix closes a memory-corruption bug in the bundled Brotli decoder that can lead to remote code execution. Others close gaps in TLS hostname checks and DNS lookups. There is no confirmed exploitation yet, but the details are public.
Do this within 48 hours
- Upgrade to Node.js 22.23.4, 24.22.1 or 26.12.1 (or newer) everywhere Node runs.
- Rebuild and redeploy container images and restart long-running processes.
- Move off Node 18 and 20. They are end of life and will not be fixed.
Key facts
| Released | 21 October 2026 |
|---|---|
| Fixed in | 22.23.4, 24.22.1, 26.12.1 |
| Issues | 10 CVEs: 4 High, 3 Medium, 3 Low |
| Most serious | CVE-2026-111497, an out-of-bounds write in the Brotli decoder (possible remote code execution) |
| Exploitation | None confirmed at the time of writing |
| Not fixed | End-of-life lines: 18.x, 20.x and 25.x |
| Also included | Updated root certificates and a block on the compromised eMudhra CA keys |
All ten vulnerabilities
| CVE | Severity | Lines | What it is |
|---|---|---|---|
| CVE-2026-111497 | High | 22, 24, 26 | Out-of-bounds write in the bundled Brotli decoder |
| CVE-2026-106069 | High | 22, 24, 26 | TLS hostname check bypass when the host loosely resolves to an IP address |
| CVE-2026-105483 | High | 24, 26 | TLS hostname check bypass with IP addresses written in full-width digits |
| CVE-2026-105482 | High | 22, 24, 26 | dns.resolve truncates names that contain a NUL character |
| CVE-2026-106072 | Medium | 22, 24, 26 | Non-canonical IPv4 hostnames let a certificate's DNS names vouch for an IP address |
| CVE-2026-105481 | Medium | 22, 24, 26 | A keep-alive socket can accept a response that was sent before the request |
| CVE-2026-106074 | Medium | 22, 24, 26 | crypto.randomUUID() and randomInt() repeat values in
startup snapshots and single executable apps |
| CVE-2026-106073 | Low | 22, 24, 26 | Permission Model bypass through fs.realpathSync |
| CVE-2026-106070 | Low | 26 | ZIP reader returns attacker-controlled bytes after a failed header check |
| CVE-2026-106071 | Low | 26 | Permission Model grants too much file access through wildcard paths |
The four High issues explained
Brotli decoder: possible remote code execution (CVE-2026-111497)
Brotli is a compression format, marked br in HTTP headers. Node.js ships its own
copy of the Brotli library, and a crafted compressed stream could make the decoder write past
the end of its buffer. Memory corruption like this can lead to code execution inside your Node
process. The bug was reported by OpenAI's Codex Security team.
You are exposed wherever Node decompresses Brotli data that someone else controls. In our experience, the common places are:
- Outbound requests to URLs you do not control. Webhook senders, link
previews, scrapers, proxies and AI agents that fetch pages. Node's built-in
fetch()decompressesbrresponses for you. - Incoming request bodies marked
Content-Encoding: br, if your framework or middleware inflates them. - Uploaded or downloaded files that your code decompresses.
- Direct calls to
zlib.brotliDecompress(),brotliDecompressSync()orcreateBrotliDecompress().
TLS hostname bypasses (CVE-2026-106069, CVE-2026-105483)
When a Node client connects over TLS, it checks that the server's certificate matches the host it meant to reach. Both bugs let that check pass when it should fail, in cases where the host is, or loosely looks like, an IP address. An attacker who can intercept traffic could then pose as the real server. The Medium-rated CVE-2026-106072 is a related problem with the same fix: Node now rejects non-canonical IP addresses.
This matters most for services that call other services by IP address, such as internal APIs, databases and hosts behind load balancers.
DNS name truncation (CVE-2026-105482)
dns.resolve stopped reading a hostname at a NUL character, so it could look up a
different name from the one your code checked. If you accept hostnames from users, for example
in a webhook or URL-fetch feature with an allow-list, an attacker could pass the check and
reach somewhere else. Node now rejects names containing NUL characters.
The Medium and Low issues
- Keep-alive responses (CVE-2026-105481). On a reused connection, Node could accept a response the server wrote before the request was sent. A hostile or confused server could feed your client the wrong answer.
- Repeating random values (CVE-2026-106074). If you build startup snapshots or single executable applications, random values cached at build time could be reused by every copy. Rebuild those artefacts after upgrading.
- Permission Model (CVE-2026-106073, CVE-2026-106071). Only relevant if you
run Node with
--permissionas a sandbox. Two bugs let code read or reach files it should not. - ZIP reader (CVE-2026-106070). In Node 26's ZIP support, a file that fails its header check could still hand back bytes chosen by the attacker.
Bundled components updated
The releases also update several libraries that Node ships inside itself, some to address public vulnerabilities:
| Component | 22.23.4 | 24.22.1 | 26.12.1 |
|---|---|---|---|
undici (powers fetch()) |
6.29.1 | 7.30.1 | 8.12.2 |
| c-ares (DNS) | 1.34.9 | 1.34.9 | 1.34.9 |
| OpenSSL | 3.5.9 | 3.5.9 | not listed |
| Root certificates | NSS 3.131.1 | NSS 3.131.1 | NSS 3.131.1 |
All three releases also reject certificate chains that contain blocked public keys, which the Node.js advisory ties to the eMudhra intermediate CA compromise. See the eMudhra section of the advisory.
If your project also installs undici from npm as its own dependency, that copy is
separate from the one inside Node. Run npm ls undici and update it as well.
Find every Node.js runtime
Node tends to run in more places than anyone has written down. Check:
- Servers and containers, including base images such as
node:22and any image pinned to an exact older version. - Serverless functions. Managed runtimes are updated by your provider on their own schedule; functions you deploy as container images are updated by you.
- CI/CD runners and build tools, which often pull untrusted code and packages.
- Desktop apps built on Electron, which bundle their own Node and need an Electron update.
- Developer machines, especially anyone still on 18 or 20.
# The version you are running
node -v
# The versions of the libraries bundled inside it
node -p "process.versions"
# The Node version inside a container image
docker run --rm --entrypoint node your-image:tag -v
How to upgrade
- Pick the fixed release for your line: 22.23.4, 24.22.1 or 26.12.1. If you are on 18 or 20, move to 22 or 24 and test, because these are major-version jumps.
- Update every place the version is set: Dockerfiles,
.nvmrc, theenginesfield inpackage.json, CI settings and serverless runtime settings. - Rebuild images from fresh base layers and redeploy.
- Restart long-running processes. A process keeps the old Node until it restarts.
- Rebuild snapshots and single executable apps if you produce them.
# nvm
nvm install 24.22.1 && nvm alias default 24.22.1
# Dockerfile: pin the patched release explicitly
FROM node:24.22.1-slim
# Rebuild without reusing old layers
docker build --pull --no-cache -t your-image:tag .
# GitHub Actions
- uses: actions/setup-node@v4
with:
node-version: 24.22.1
If you cannot upgrade today
These reduce risk. They do not fix the bugs.
Use them only for the hours until the upgrade is done.
- Refuse Brotli-encoded request bodies at your reverse proxy, unless you genuinely need them.
- Ask for gzip only when fetching from services you do not control, by
setting your own
Accept-Encodingheader. A hostile server can ignore this, so it only helps against well-behaved services. - Keep certificate checks on. Never set
rejectUnauthorized: falseorNODE_TLS_REJECT_UNAUTHORIZED=0, and connect to services by hostname rather than IP address where you can. - Reject hostnames containing NUL characters before passing user input to DNS lookups.
# nginx: refuse Brotli-encoded request bodies
if ($http_content_encoding ~* "br") {
return 415;
}
// Ask external services for gzip rather than Brotli
const res = await fetch(url, {
headers: { 'accept-encoding': 'gzip, deflate' },
});
// Reject hostnames with NUL characters before DNS lookups
if (hostname.includes('\0')) {
throw new Error('Invalid hostname');
}
Common questions
Is anyone exploiting this yet?
No exploitation had been confirmed at the time of writing. The fixes are public, though, and attackers study them, so the window is short.
Does npm audit catch this?
No. These bugs are in the Node.js runtime, not in your npm packages. npm audit is
still worth running for your dependencies, including the separate undici package from
npm.
We are on Node 20. Is there a patch?
No. Node 20 reached end of life and gets no further fixes. Plan the move to 22 or 24 now.
Do Express, Next.js or NestJS need updating?
Not for these fixes. Upgrading Node fixes them for every framework that runs on it. Keep your framework current anyway.
How TechMaven can help
We build and run Node.js services in production: APIs, real-time systems, Next.js front ends and the pipelines that deploy them. We can find every runtime and image, roll the upgrade out safely, and handle the jump off Node 18 or 20 if you are behind. Get in touch and a senior engineer will reply within one business day. For the PHP and certificate issues from the same week, see the October 2026 security advisory.
Sources: Node.js October 2026 security releases (opens in a new tab), release notes for 22.23.4 (opens in a new tab), 24.22.1 (opens in a new tab) and 26.12.1 (opens in a new tab), and Node.js release status (opens in a new tab). Accurate as of 23 October 2026. Always confirm versions against the official advisory before you act.