← Blog
Article

Node.js Vulnerabilities in 2026: Every CVE, the npm Worms and What to Patch

Node.js vulnerabilities in 2026: the Node2Shell Brotli RCE (CVE-2026-111497), all five security releases, the npm worms and the versions to run today.
13 min readSecurityNode.jsnpmSupply Chain

By Assim ElHammouti, Founder and Lead Engineer, NordbeamPublished Updated

Short answer

Which Node.js vulnerabilities matter right now?

The most serious Node.js vulnerability of 2026 is CVE-2026-111497, an out-of-bounds write in the bundled Brotli decoder that can lead to remote code execution. It was fixed on 21 October 2026. Run Node.js 22.23.4, 24.22.1 or 26.12.1 or later; Node 20 is end-of-life and gets none of these fixes. Compiled by Nordbeam, a development studio in Gothenburg and Malmö.

Patch to
22.23.4 · 24.22.1 · 26.12.1
Latest security release
21 October 2026
No longer patched
Node 20, Node 25 and older

Node.js has shipped five security releases in 2026: in January, March, June, July and October. Between them they fix around 50 vulnerabilities in Node.js core. The latest, on 21 October, fixes a decoder bug that the project's own advisory says can lead to remote code execution.

That was not the hardest part of the year for Node.js teams, though. Over the same months, the npm registry saw three large supply-chain attacks: a hijacked axios release in March, a worm that went through TanStack's own release pipeline in May, and ChainDrop in August, which Microsoft says reached more than 400 packages.

This article covers both: what changed in Node.js core, what the npm attacks had in common, and the exact versions and settings to use today. It is written for teams running Node.js in production, and every version number links back to its source. If you also run Bun, PHP or Ruby, we have written the same roundup for Bun, PHP and Ruby and Rails.

What is the most serious Node.js vulnerability right now?

CVE-2026-111497, a flaw in the Brotli decoder that ships inside Node.js, nicknamed "Node2Shell". It affects Node 22, 24 and 26, and the fix is in 22.23.4, 24.22.1 and 26.12.1, released on 21 October 2026.

The official advisory explains the mechanism. An invalid block switch in the compressed stream was reported as "need more input" instead of as a format error. The streaming decoder therefore kept appending bytes to an eight-byte internal buffer, past its end. Anyone who can make your application decompress Brotli data with node:zlib can corrupt process memory, "which can lead to a crash, disclosure of process memory, or remote code execution."

The bug is in Google's Brotli library itself, versions 1.0.3 to 1.2.0, so it is not specific to Node.js. It also hit Bun and the Python brotli package. Node.js rates it High. Google, which assigned the CVE, rates it Critical, CVSS v4.0 9.2 (NVD record), and Singapore's Cyber Security Agency scores it 9.8 in its alert.

You are exposed if any code path inflates Brotli data that came from outside, for example:

  • Request bodies sent with Content-Encoding: br that your server or middleware decompresses.
  • Uploaded or downloaded .br files processed with zlib.brotliDecompress or createBrotliDecompress.
  • Outgoing HTTP calls. Node's built-in fetch() (undici) decompresses br responses with zlib.createBrotliDecompress, so an HTTP request to a server you do not control reaches the decoder.

The last point makes this broader than it looks. Webhooks, link previews, scrapers and any "fetch this URL for me" feature are all in scope. There is no configuration flag that removes the risk; the fix is the upgrade.

10

Vulnerabilities in the Node.js security release of 21 October 2026

4
rated High, including the Brotli decoder RCE (CVE-2026-111497)
3
patched lines: 22.23.4, 24.22.1 and 26.12.1
0
fixes for Node 20, which reached end-of-life on 30 April 2026

Everything in the October 2026 release

CVESeverityWhat it isLines
CVE-2026-111497HighBrotli decoder out-of-bounds write; possible RCE22, 24, 26
CVE-2026-105482Highdns.resolve*() truncates names at a NUL byte, so attacker.example\0.trusted.example resolves as the attacker's domain22, 24, 26
CVE-2026-105483HighTLS hostname check bypass when an IP is written with fullwidth digits24, 26
CVE-2026-106069HighTLS hostname check bypass when a host loosely resolves to an IP (for example a leading-zero IPv4 read as octal)22, 24, 26
CVE-2026-105481MediumA keep-alive socket accepts a response written before the request was sent22, 24, 26
CVE-2026-106072MediumNon-canonical IPv4 hostnames (127.1, 0x7f.0.0.1) can be authenticated by a DNS SAN22, 24, 26
CVE-2026-106074Mediumcrypto.randomUUID() and randomInt() caches are saved into startup snapshots and single executable apps, so every process repeats the same values22, 24, 26
CVE-2026-106073LowPermission Model bypass through fs.realpathSync22, 24, 26
CVE-2026-106070LowZipFile returns attacker-controlled bytes after a failed header check26
CVE-2026-106071LowPermission Model over-grant through wildcard paths26

The same release updates c-ares, OpenSSL (22 and 24), SQLite (22), undici and the bundled CA certificates. That last update follows an intermediate CA compromise at eMudhra.

What did each Node.js security release in 2026 fix?

Every release this year followed the same pattern: a small number of High-severity bugs in network-facing code, a long tail of Medium and Low issues, and dependency updates. Here are the five side by side. The counts are taken from each official post.

ReleaseFixed versionsIssues (High)Headline bugs
21 Oct 202622.23.4, 24.22.1, 26.12.110 (4)Brotli decoder RCE, TLS hostname bypasses, DNS NUL truncation
29 Jul 202622.23.2, 24.18.1, 26.5.111 (3)HTTP/2 use-after-free (CVE-2026-56848), HTTP/2 memory exhaustion, Permission Model over-grant
18 Jun 202622.23.0, 24.17.0, 26.3.112 (2)WebCrypto AES integer overflow, TLS wildcard bypass via Unicode dots
24 Mar 202620.20.2, 22.22.2, 24.14.1, 25.8.29 (2)__proto__ header crash (CVE-2026-21710), SNI callback crash, V8 HashDoS
13 Jan 202620.20.0, 22.22.0, 24.13.0, 25.3.08 (3)Uninitialised memory via vm timeouts, symlink Permission Model bypass, HTTP/2 HEADERS crash

Two things stand out. First, several October fixes are repairs of June fixes: CVE-2026-105482 is an incomplete fix of the June DNS bug, and CVE-2026-105483 is a regression after the June TLS fix. Patching once is not enough; you have to keep up.

Second, March was the last release for Node 20. Every Node 20 server running today has missed the June, July and October fixes.

Where do Node.js vulnerabilities come from?

Most core CVEs in 2026 sit in protocol handling and in the native libraries that Node.js bundles, not in JavaScript APIs that you call directly. That matters, because there is nothing you can configure around a bug in the HTTP/2 or Brotli layer. You can only upgrade.

Where the 2026 vulnerabilities sit
Your application

Routes, auth, input validation

Your code and your configuration

npm dependencies

Frameworks and transitive packages

Next.js RCEs (October), the axios, TanStack and ChainDrop compromises

Node.js core

http, http2, tls, dns, zlib, crypto, Permission Model

TLS and DNS identity bugs, HTTP/2 crashes, 14 Permission Model bypasses

Bundled native code

Brotli, nghttp2, llhttp, OpenSSL, c-ares, undici

The Brotli out-of-bounds write, the nghttp2 use-after-free

The bottom two layers produced most of this year's core CVEs, and only an upgrade fixes them.

Four patterns cover nearly everything in this year's releases.

1. TLS and DNS disagree about what a name is. NUL bytes, Unicode dots, fullwidth digits, octal IPv4 addresses, SNI case and session reuse: in each case the certificate checker and the resolver read the same hostname differently. An attacker who controls a name can then get a certificate accepted for a host it was not issued for. If you connect to internal services by IP, or pin certificates to hostnames, these bugs are aimed at you.

2. HTTP/2 and the HTTP parser keep producing crashes. Almost every release has an HTTP/2 denial of service, and July added a use-after-free (CVE-2026-56848) and a header-count bug (CVE-2026-58044). The latter lets a forwarding proxy disagree with the backend about where a request ends, which is the setup for request smuggling.

3. Memory-safety bugs in bundled C code. The Brotli decoder, nghttp2 and the WebCrypto AES path are all native code. These are the bugs that move from "crash" to "remote code execution".

4. The Permission Model is bypassed in every release. That is the subject of the next section.

Is the Node.js Permission Model a security sandbox?

No. The Node.js documentation calls it a "seat belt" that stops trusted code from accidentally touching files or resources. It states plainly that it "does not provide security guarantees in the presence of malicious code."

The 2026 releases bear that out. Counting all five posts, we found 14 Permission Model bypasses. They came through process.report, FileHandle.utimes(), chmod() and chown(), realpathSync, trace_events, symlinks, Unix domain sockets and wildcard paths. Several were incomplete fixes of earlier ones.

Use --permission to catch mistakes in code you trust. To run code you do not trust, use operating-system isolation: a container with a read-only filesystem, a separate user, seccomp or AppArmor profiles.

Which Node.js versions are still supported?

Node.js 22, 24 and 26. Node 20 reached end-of-life on 30 April 2026, and the odd-numbered Node 25 followed on 1 June. The project's own wording is that end-of-life versions "are always affected when a security release occurs."

Node.js release lines, October 2026
  1. EOL Apr 2026

    Node 20

    • Unsupported; last release 20.20.2
    • Missed the June, July and October fixes
  2. EOL Apr 2027

    Node 22

    • Maintenance LTS
    • Patch to 22.23.4
  3. EOL Apr 2028

    Node 24

    • Maintenance LTS since 20 Oct 2026
    • Patch to 24.22.1
  4. EOL Apr 2029

    Node 26

    • Active LTS from 28 Oct 2026
    • Patch to 26.12.1
Three lines get security fixes today; Node 20 stopped at 20.20.2 in March.
LineStatus on 24 Oct 2026End of lifeVersion to run
Node 26Current, becomes Active LTS on 28 Oct 202630 Apr 202926.12.1 or later
Node 24Maintenance LTS since 20 Oct 202630 Apr 202824.22.1 or later
Node 22Maintenance LTS30 Apr 202722.23.4 or later
Node 25End-of-life1 Jun 2026Move to 26
Node 20End-of-life30 Apr 2026Move to 24 or 26

Dates are from the Node.js release schedule. For new production work we would start on Node 24, or on 26 once it becomes LTS on 28 October. Node 22 is still patched, but it has six months left, which is less than most upgrade projects take to plan.

How did the 2026 npm supply-chain attacks work?

The same way each time: steal a publishing credential, ship a release with a script that runs on install, and use whatever that script steals to publish more. The three big incidents differed only in how they got the first credential.

axios, 31 March 2026. A maintainer account was compromised and two releases, axios@1.14.1 and axios@0.30.4, were published with a new dependency, plain-crypto-js@4.2.1. That package's postinstall script dropped a cross-platform remote access trojan that went after .ssh and .aws. The bad versions were live for about three hours, according to Orca Security's analysis. Projects that installed axios in that window, without a lockfile pinning an older version, pulled the trojan.

TanStack and "Mini Shai-Hulud", May 2026. This one did not need a stolen password. Orca reports that the attacker chained GitHub Actions weaknesses: a pull_request_target workflow poisoned the Actions cache, and the release workflow then leaked OIDC tokens. The malicious versions, 373 of them across 169 npm package names, were published through the legitimate pipeline. They therefore carried valid npm provenance. The payload stole GitHub, npm, cloud, Kubernetes and Vault credentials and spread from one package to the next, like the original Shai-Hulud worm of 2025.

ChainDrop, August 2026. Microsoft's write-up describes more than 400 compromised packages from unrelated publishers, including keyv, flat-cache and cache-manager.

  • Install hook. A preinstall hook ran setup.mjs, which launched an obfuscated, Bun-based payload.
  • Theft. It harvested npm, GitHub and cloud credentials, and used them to read AWS, Kubernetes and Vault secrets.
  • Spread. For every package a stolen token could publish, it downloaded the latest tarball, inserted itself, bumped the patch version and republished.
  • Persistence in repositories. It also wrote .claude/settings.json and .vscode/tasks.json files into repositories, to spread from developer to developer.
How an npm worm spreads
1 · Access

Publishing token stolen

Phished, leaked, or lifted from a CI runner

2 · Publish

Patch release with a preinstall hook

Often no matching commit or tag

3 · Install

npm install runs the hook

On laptops and CI runners

4 · Spread

Steals tokens, republishes

Every package the victim can publish

Where to break the chain

Install scripts off by default, and a cooldown before any new version is installed

  • ✓ lockfile committed; npm ci in CI
  • ✓ trusted publishing with short-lived tokens for your own packages
  • ✓ provenance checked, but not treated as proof of safety
A worm needs two things from you: a brand-new version it can reach, and an install that runs its script.

How do you protect a Node.js project from npm supply-chain attacks?

Make new releases wait, stop install scripts from running by default, and make your own publishing pipeline hard to borrow. In order of effort:

  1. Commit the lockfile and install with npm ci in CI and in Docker builds. A lockfile means a new malicious patch release only reaches you when someone updates it on purpose.
  2. Add a release-age cooldown. Microsoft's ChainDrop guidance is to upgrade to npm CLI v12 and use its min-release-age setting. pnpm has minimumReleaseAge, and so does Bun, in bunfig.toml (see our Bun article). The malicious axios versions were live for about three hours, so a cooldown of a few days would have kept them out entirely.
  3. Turn off lifecycle scripts by default with ignore-scripts=true in .npmrc. Then run the few build steps you actually need, such as native modules, explicitly. The axios trojan ran from a postinstall script, and ChainDrop from a preinstall hook.
  4. Treat provenance as a signal, not a guarantee. The TanStack versions had valid provenance because the attacker used the real pipeline.
  5. Harden your own release workflow if you publish packages. Use trusted publishing (OIDC) instead of long-lived tokens. Never run untrusted pull-request code in a pull_request_target workflow, and do not share caches between untrusted jobs and release jobs.
  6. Run npm audit in CI, but know its limits. It reports known advisories against your installed versions; it does not catch a malicious release in its first hours.

Attention

If you installed a compromised version

Rotate credentials from a clean machine, not the infected one. Purge npm and yarn caches on developer machines and shared CI runners, and rebuild images from a known-good baseline. Microsoft also lists Math_Symbol.js and Math_init.js as ChainDrop artifacts to look for.

Which npm package vulnerabilities should you check in 2026?

Next.js is the urgent one. On 20 October 2026, two unauthenticated remote code execution flaws were published, both CVSS v4.0 9.5, per Singapore's CSA alert:

  • GHSA-673q-mjm6-r5xr affects App Router applications using Cache Components, when a "use cache" function returns multiple typed arrays. No CVE ID had been issued at publication.
  • CVE-2026-96889 comes from a memory bug in an upstream library used for Image Optimisation, on glibc-based Linux.

Both affect 16.x before 16.4.1 and 10.x to 15.x before 15.5.28. Upgrade to those versions or later.

Beyond Next.js, the most important "package vulnerability" of 2026 was not a bug but the compromised releases above. Check your lockfiles for axios@1.14.1, axios@0.30.4 and plain-crypto-js, and for any ChainDrop-era versions of keyv, flat-cache or cache-manager. Use the version lists in Microsoft's and your security vendor's advisories.

What should you patch first?

  1. Upgrade Node.js to 22.23.4, 24.22.1 or 26.12.1, and rebuild container images, because a node:22 base image you pulled last month still has the old binary. Check with node -v in the running container, not on your laptop.
  2. Move off Node 20 and 25. They will not get the Brotli fix.
  3. Upgrade Next.js to 16.4.1 or 15.5.28 or later if you run it.
  4. Search your lockfiles for the compromised axios and ChainDrop versions.
  5. Add a cooldown and turn off install scripts for every project and CI pipeline.
  6. Stop relying on --permission as isolation for untrusted code.

Nordbeam builds production systems on TypeScript and Node.js. If you have an end-of-life Node line or a dependency tree you are no longer sure about, our software development team can scope the upgrade with you.

What is CVE-2026-111497?
CVE-2026-111497 is a High-severity Node.js vulnerability in the bundled Brotli decoder, fixed on 21 October 2026. Malformed Brotli input makes the streaming decoder write past an eight-byte internal buffer, which can crash the process, leak memory or lead to remote code execution. It affects Node 22, 24 and 26 and is fixed in 22.23.4, 24.22.1 and 26.12.1.
Does the Brotli vulnerability affect fetch() in Node.js?
Yes, if the response is Brotli-compressed. Node's built-in fetch() is implemented by undici, which decompresses responses with Content-Encoding: br using zlib.createBrotliDecompress. A request to a server you do not control can therefore reach the vulnerable decoder. Upgrading Node.js is the fix.
Is Node.js 20 still safe to use?
No. Node.js 20 reached end-of-life on 30 April 2026. Its last release was 20.20.2 in March, so it is missing the June, July and October 2026 security fixes, including the Brotli remote code execution fix. Move to Node 24 or 26.
Which Node.js version should I use in production?
Node 24 (24.22.1 or later) is a safe default today, and Node 26 becomes Active LTS on 28 October 2026 with support until April 2029. Node 22 is still patched (22.23.4 or later) but reaches end-of-life on 30 April 2027.
How do I check npm packages for vulnerabilities?
Run npm audit to compare your installed versions against known advisories, and run it in CI so new advisories fail the build. It does not detect a malicious release in its first hours, so combine it with a committed lockfile, npm ci, a release-age cooldown and disabled install scripts.
What is the Shai-Hulud npm worm?
Shai-Hulud was a self-replicating npm worm first seen in September 2025. It stole npm tokens from developers who installed an infected package and used them to publish infected versions of the victims' own packages. The May 2026 TanStack compromise was reported as Mini Shai-Hulud, and ChainDrop in August 2026 spread the same way.
Is the Node.js Permission Model enough to run untrusted code?
No. The Node.js documentation describes it as a seat belt for trusted code and says it does not provide security guarantees against malicious code. In 2026 alone there were 14 Permission Model bypasses across the five security releases. Use containers, separate users or seccomp and AppArmor profiles for isolation.
Does this Node.js vulnerability affect Bun or Deno?
Bun, yes. The bug is in Google's Brotli library (1.0.3 to 1.2.0), which Bun bundles too, and Bun fixed it in version 1.4.4 on 22 October 2026. Bun's fetch() decodes Brotli responses automatically, so it is reachable the same way. The Python brotli package was fixed in 1.2.1. For Deno, check its own release notes.

Stuck on an old Node.js line?

Tell us what you run and where it is deployed. We will tell you what an upgrade to a supported Node.js version involves, and what it costs to stop doing it by hand.

Start the Conversation →

Get in Touch

Which workflow should AI improve first?

Book a practical review of one high-value workflow. You'll speak directly with Assim, Nordbeam's founder and lead engineer.
Email directly
Email
hello@nordbeam.io
Locations
Gothenburg & Malmö, Sweden
Response time
Within 24 hours