Node.js Security Release Oct 2026: Upgrading on a VPS

Published

Node.js Security Release Oct 2026: Upgrading on a VPS

On 21 October 2026 — the same day PHP shipped its PHP2Shell fixes — the Node.js project released security updates for all three supported lines. Ten CVEs are fixed; four are rated High, the highest severity in this release.

There are no workarounds. The only fix is upgrading, and on a typical VPS “upgrading Node” has a few traps where you think you’re patched and you aren’t.

The short version

Fixed versions 22.23.4, 24.22.1 (LTS), 26.12.1 (Current)
Most serious bug CVE-2026-111497 — Brotli decoder out-of-bounds write that can lead to remote code execution
Workarounds None. Upgrade.
Node 20 or older? End-of-life. The project’s position is that EOL versions are always affected and won’t be fixed.

Source: the official Node.js security release post.

What was fixed

The four High-severity issues:

  • CVE-2026-111497 — Brotli RCE (22.x, 24.x, 26.x). In the official wording: “An attacker who can supply Brotli data that an application decompresses with node:zlib can corrupt process memory, which can lead to a crash, disclosure of process memory, or remote code execution.” Any code path that decompresses Brotli from an untrusted source is in scope — think HTTP clients that transparently decode Content-Encoding: br responses, or servers that accept compressed request bodies. Rather than auditing which libraries in your tree touch node:zlib, upgrade.
  • CVE-2026-106069 — TLS hostname bypass when a host loosely resolves to an IP with leading-zero octets (22.x, 24.x, 26.x).
  • CVE-2026-105483 — TLS hostname bypass with fullwidth digits in an IP address (24.x, 26.x).
  • CVE-2026-105482 — dns.resolve*() / dns.reverse() truncate names containing a NUL character (22.x, 24.x, 26.x).

The release also fixes six Medium/Low issues (keep-alive response handling, DNS SAN matching, crypto.randomUUID() values repeating in snapshots/SEAs, and Permission Model bypasses) and updates bundled c-ares, Undici, CA certificates (eMudhra intermediate CA compromise), OpenSSL (22.x, 24.x) and SQLite (22.x).

Step 1: Check what’s actually running

node -v in your shell is not the whole answer. The process serving traffic may be running a different binary.

# Your shell's Node
node -v

# The Node version PM2 is actually using for each app
pm2 list
pm2 info my-app | grep -i "node.js version"

# Inside a container
docker exec <container> node -v

You’re patched only if the version your running app reports is at least 22.23.4, 24.22.1 or 26.12.1 on its line.

Step 2: Upgrade — by install method

nvm

nvm install 24                 # pulls the latest 24.x (24.22.1 or newer)
nvm alias default 24
node -v

Staying on 22.x is fine too: nvm install 22 gets 22.23.4 or newer. Global npm packages are per-version under nvm, so reinstall PM2 for the new version (npm install -g pm2) or use nvm install 24 --reinstall-packages-from=current.

NodeSource (apt)

sudo apt update
sudo apt install --only-upgrade nodejs
node -v

If node -v still shows an old version, the NodeSource repository on your server may point at an older major line — check /etc/apt/sources.list.d/ before assuming you’re patched.

Docker

Updating Node on the host does nothing for containers. Rebuild every image that bundles Node, forcing a fresh base image:

docker build --pull --no-cache -t my-app .
docker run --rm my-app node -v

Then redeploy the containers. If your Dockerfile pins an exact Node version (FROM node:24.10.0-alpine), bump it — a pinned tag never picks up fixes.

Step 3: Make PM2 actually use the new Node

This is the trap that leaves “upgraded” servers vulnerable. PM2’s daemon keeps running on the Node binary it was started with, and pm2 restart alone doesn’t change that.

pm2 update                     # restarts the PM2 daemon on the current Node
pm2 info my-app | grep -i "node.js version"

If you installed Node with nvm and use pm2 startup, the generated systemd unit hardcodes the path to the old version’s directory (something like ~/.nvm/versions/node/v22.x.x/bin). After a reboot, PM2 would come back on the old Node. Regenerate it:

pm2 unstartup systemd          # if it prints a sudo command, run that
pm2 startup systemd            # run the sudo command it prints
pm2 save

Verify after the next reboot with pm2 info again.

Step 4: Test before you call it done

Moving within a release line (22.x → 22.23.4) is low risk. Jumping majors (22 → 24) can break native modules and older dependencies:

  • Run your test suite against the new version first, or take a server snapshot / try it on staging.
  • Rebuild native modules if you changed majors: npm rebuild.
  • With PM2 cluster mode, pm2 reload my-app swaps workers without downtime once the daemon is on the new Node. A full zero-downtime deploy pipeline makes this routine.

Still on Node 20?

Node 20 is past end-of-life, so it gets none of these fixes, and the Node project says EOL versions are always affected by new security releases. Plan the move to 22 or 24 now rather than at the next emergency. If your server still has PHP installed alongside Node, check the PHP2Shell guide too — both runtimes were patched on the same day.


CVE details and fixed versions are from the Node.js October 2026 security release post.