Guide

Still on Node.js 20? This week's security fixes skip you — a safe move to 22 or 24

By Aman Singh · Published · 9 min read

On 21 October 2026 Node.js released fixes for ten vulnerabilities, including Node2Shell (CVE-2026-111497), a critical remote-code-execution bug in the bundled Brotli decoder. The fixes shipped for the 22, 24 and 26 lines — 26.12.1, 24.22.1 and 22.23.4. They did not ship for Node.js 20, which is end of life and receives no security fixes at all.

That is the trap: on Node.js 20 there is no patch version to move to. "Bump the Node version" does nothing, because the fix only exists on newer lines. A Node 20 app stays exposed to Node2Shell — and to this month's TLS and DNS fixes — until you move it to a supported line. Vercel says the same in its own advisory: "Node.js 20 reached end of life and will not receive this fix." This guide is the safe way to make that move.

Want the upgrade done and the breakage fixed for you? Security patching →

Why this week's fix skips Node 20

Node.js security fixes are backported only to lines that are still in support. Node.js 20 ("Iron") reached end of life in 2026, so it dropped out of that list. The October release carried the fix to 22, 24 and 26; there is no 20.x build that contains it, and there will not be one.

Node2Shell is the headline, but the same releases also fixed TLS hostname-check bypasses and a DNS truncation bug, and refreshed the root certificates (blocking the compromised eMudhra intermediates). Every one of those skips Node 20 as well. Staying on 20 is not "one unpatched CVE"; it is a runtime that no longer gets any.

Which line to move to

TargetWhyChoose it when
22.23.4LTS, closest to Node 20 — the smallest behaviour changeYou want the least risk and the fastest move
24.22.1LTS, supported into 2028Most apps: the best balance of support runway and stability
26.12.1Newest LTS line (active from 28 October 2026)You want the longest runway and can absorb a bigger jump

For most teams I recommend 24.22.1: it is a current LTS with support into 2028, and the jump from 20 is well-trodden. Pick 22.23.4 if you need the smallest possible change today and will move again later.

A safe move, in order

  1. 1
    Find every place Node 20 runs. Your laptop, CI matrix, the Dockerfile FROM, the Vercel project setting, the Lambda runtime, and any PM2 or systemd host. Each is a separate change.
  2. 2
    Install the target locally and reinstall from scratch. Deletenode_modules and the lock file so native add-ons (such asbetter-sqlite3, bcrypt, sharp) rebuild for the new ABI, then run your full test suite.
    Terminal
    # install a supported line locally (nvm shown; fnm is the same idea)
    nvm install 24.22.1 && nvm use 24.22.1
    
    # fresh install so native modules rebuild against the new ABI
    rm -rf node_modules package-lock.json
    npm install
    npm test
  3. 3
    Update the version in every environment and redeploy. Bumpengines.node, the Dockerfile, the CI matrix and the platform setting together, so nothing silently falls back to 20.
    By environment
    # package.json: state the floor you now support
    { "engines": { "node": ">=22.23.4" } }
    
    # Dockerfile: pin a patched line, then rebuild and redeploy
    FROM node:24.22.1-alpine
    
    # Vercel: Project Settings -> Node.js Version -> 24.x, then redeploy
    # AWS Lambda: set the runtime to nodejs24.x (or nodejs22.x)
    # PM2 / systemd host: install the new Node, then restart the service
    pm2 restart all          # or: sudo systemctl restart my-api
  4. 4
    Restart long-running processes. A running PM2 or systemd process keeps the old binary until it restarts; pulling a new image does not change a container that is already running.
  5. 5
    Verify on the deployed machine, not only locally (see below).

What usually breaks (and what doesn't)

Going from 20 to 22 or 24 is a routine upgrade for most applications, but a few things are worth checking before you deploy:

  • Native modules. Anything compiled (node-gyp based) needs a version with prebuilt binaries for the new line, or a working build toolchain. Most breakage lives here; the fresh reinstall above surfaces it.
  • Deprecated APIs. Long-deprecated corners (the legacy url.parse behaviour, the punycode built-in, the old Buffer() constructor) warn or are gone. Grep your code and dependencies for them.
  • Pinned Node in tooling. .nvmrc, Volta pins, CI images and any Docker base you forgot — these keep an app on 20 after you "upgraded".
  • Certificate checks are stricter. This month's TLS fixes mean connections to hosts written as non-canonical IP addresses can now fail certificate validation. Test any internal service you reach by raw IP.
  • What rarely breaks: standard HTTP servers, Express/Fastify apps, and pure-JS dependencies. OpenSSL 3 was already in Node 20, so that jump is behind you.

Verify the fix landed

Confirm the running runtime is both on a new line and actually patched. The surest test is a zlib constant that only the patched Brotli decoder exposes — it is present on every fixed build and absent on every Node 20 build.

Terminal
# on the deployed machine or container, not just your laptop
node -v
node -p "require('zlib').constants.BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH"
# patched builds print -17; unpatched (incl. all of Node 20) print undefined

Common questions

Can I just install the latest Node 20 patch to fix Node2Shell?+
No. Node.js 20 is end of life, so no 20.x release contains the CVE-2026-111497 fix. The only fix is moving to a supported line: 22.23.4, 24.22.1 or 26.12.1.
Should I go to 22, 24 or 26?+
24.22.1 is the balanced choice for most apps — a current LTS supported into 2028. 22.23.4 is the smallest jump from 20 if you want minimal change. 26.12.1 is the newest LTS line and gives the longest runway.
I'm on Vercel or AWS Lambda — do they handle this?+
They patch the runtime you select, but they can't select a supported major for you. If your project or function is set to Node 20, change it to 22.x or 24.x and redeploy. Vercel's advisory says to set 22.x or 24.x in project settings or engines.node, then redeploy.
How do I know the upgrade actually took effect in production?+
Run node -v and the zlib constant check on the deployed machine or container. A long-running process or a forgotten Docker base can leave production on Node 20 even after the code says otherwise.

Want the upgrade done and the breakage fixed for you?

I move Node.js apps off end-of-life lines, rebuild native modules, fix what the jump breaks, and verify every environment is on a patched runtime. See security patching or Node.js API development. Related: the Node2Shell check-and-patch guide.

Sources

Next steps

Keep reading

Need a hand with this?

Tell me what you are working on. Free scoping call, fixed quote within 48 hours.

Book a call

← All guides