Node.js shipped its third security release of 2026 on October 21, and the headline fix is a bad one: CVE-2026-111497, an out-of-bounds write in the Brotli decoder that Node's advisory says can lead to "a crash, disclosure of process memory, or remote code execution." That follows twelve fixes on June 18 and eleven on July 29.
Updated October 29, 2026. An earlier version of this page told Vercel users they had nothing to do. October showed that was too strong, and the section below says why.
Here's the part nobody writes down. Whether your deployed app picked those fixes up has almost nothing to do with you and almost everything to do with which host you clicked "deploy" on. Two apps with identical package.json files, deployed the same day, can sit on opposite sides of that line.
TL;DR
Vercel picks your Node patch version, but as of its October bulletin the patch is promised to new deployments, so redeploy after a security release (and move off Node 20, which gets no fix). Cloudflare Workers don't run Node at all. Netlify, Render, Railway, Fly and anything Docker-based freeze the Node version into your build, so you stay on whatever you shipped until you rebuild. There's a second trap on the rebuild side: if you pinned an exact version like 22.23.0 instead of a major like 22, rebuilding doesn't help either. Check process.version on the running app, not your laptop.
Two questions, not one
Most advice treats this as a single question ("is my Node up to date?"). It's really two, and they have different answers per host.
- Does the runtime move on its own? If your host manages Node as infrastructure, patches land without a deploy.
- If it doesn't, does a rebuild pick up the patch? Only if you pinned loosely. An exact version pin survives rebuilds by design. That's what pinning means.
You need a "yes" to one of those. Plenty of apps have neither, which is how a project that gets deployed twice a week can still be running a Node release from last winter.
Hosts that patch Node for you
Vercel. Its version docs are unusually direct about this: "Only major versions are available. Vercel automatically rolls out minor and patch updates when needed, such as to fix a security issue." You choose 24.x in project settings or engines.node in package.json, and Vercel picks the specific build. You couldn't pin an exact patch even if you wanted to.
What that sentence doesn't say is which deployments get the new build. Vercel's security bulletin for CVE-2026-111497 is scoped carefully: "As of October 28 at 11am PT, all new deployments on Vercel use a patched version of Node.js." It never says running deployments are patched in place, and for its temporary mitigation (below) it tells you to "Redeploy existing projects to receive this protection." Our reading, and it is a reading rather than something the bulletin states outright: a deployment that's already running keeps the runtime it was built with until you redeploy.
The rollout also took a week. On October 23 one developer reported on Vercel's forum that a redeploy on 24.x "without build cache" still logged v24.21.0, which predates the fix (24.22.1), and asked whether existing deployments would get the patch automatically. Vercel staff replied on October 27 with a link to the updated bulletin. So the practical answer on Vercel today: no version to edit, but redeploy now (the rollout was complete for new deployments as of October 28), then check that process.version reads v22.23.4 or v24.22.1 or later.
A few more lines in the bulletin matter:
- Projects still on Node 20.x "must change their Node.js version to 22.x or 24.x and redeploy." Node 20 is end of life and "will not receive this fix."
- While the rollout ran, new deployments on an unpatched version got a temporary mitigation: Vercel "disables Brotli response handling for outbound requests made through
fetch()and HTTP clients that usenode:httpornode:https." Another reason to redeploy rather than wait. - Vercel put WAF rules in front of every project the day of the release. The WAF "does not cover responses your functions fetch from other servers," and Vercel says it "reduces exposure but does not replace patching."
- Anything Node-based you run outside Vercel's managed runtime (an external backend, self-hosted Next.js, a container, CI runners, your laptop) needs upgrading "now, regardless of WAF protections."
Cloudflare Workers. Different reason, same outcome for Node's own CVEs. Workers don't run Node at all. They run Cloudflare's own runtime, workerd, which implements a subset of Node's APIs natively plus polyfills for the rest. There's no Node version to select, because there's no Node. What you set is a compatibility_date in your Wrangler config, which controls runtime behavior changes, not security patches. Cloudflare owns patching the engine.
A compatibility date is not a version pin in the security sense. It exists so Cloudflare can change default behavior without breaking old Workers. Setting an old date does not keep you on an old, unpatched engine.
Hosts that freeze it into your build
Netlify. This is the one that surprises people, and the docs say it plainly: "A build's Node.js version is initially determined by the default version preinstalled on the site's selected build image. We pin the site to that version so your builds won't change even if the build image's defaults change."
Pinned. Not rolling. You can override with .node-version, .nvmrc, or a NODE_VERSION variable, and Netlify accepts either an exact version like 20.11.1 or a major like 24, which resolves to the latest 24.x at build time. The functions runtime normally inherits whatever the build used.
Render. Resolution order is NODE_VERSION in the dashboard, then .node-version, then .nvmrc, then engines in package.json. Leave all four unset and you get a default tied to when you created the service, not to today. Render's own docs list different defaults for services created before and after specific dates. A service you spun up two years ago carries a two-year-old default until you say otherwise.
Railway. Railpack resolves the version from RAILPACK_NODE_VERSION, then engines.node, then .nvmrc, then .node-version, then mise.toml, falling back to LTS. The important detail is when: the version is resolved during the build and baked into the container image. The running container has no mechanism to swap its own Node out.
Fly, and anything you ship as a Docker image. Your FROM node:22-alpine line is the whole story. That tag resolved to a specific digest the last time you built. Until you rebuild and re-pull the base image, that's your runtime, forever, no matter how many CVEs land upstream.
"But I deploy constantly" is not a defense on its own. Rebuilding only helps if your version spec is loose enough to resolve forward. An exact pin plus daily deploys keeps you exactly as vulnerable as no deploys at all.
The table
| Host | Runtime moves on its own? | What a rebuild does |
|---|---|---|
| Vercel | Yes for new deployments; a running deployment keeps its Node | Redeploy to pick up the patch. Node 20 must move to 22.x or 24.x |
| Cloudflare Workers | Yes, Cloudflare patches workerd | No Node version to manage |
| Netlify | No, pinned to build image default | Picks up latest patch only if you set a major-only version |
| Render | No, resolved per service | Same, and the unset default tracks service creation date |
| Railway | No, baked into the image at build | Re-resolves from your spec |
| Fly / Docker | No, frozen to the base image digest | Only if you re-pull the base tag |
Read that middle column as the real question. Four of six rows say no, and the one "yes" still needs a redeploy.
Check what you're actually running
Three sources of truth people confuse, in increasing order of usefulness.
Your local node -v tells you about your laptop. engines.node in package.json tells you what you asked for. Neither tells you what booted in production.
// Add to any API route, hit it once, then remove it.
export function GET() {
return Response.json({
node: process.version,
platform: process.platform,
});
}
For build-time visibility, prepend node -v && to your build command and read it in the deploy log. On Netlify and Render that's the fastest way to confirm whether your .node-version file is being honored at all, which is a common silent failure when the file has a stray newline or a v prefix the resolver doesn't expect.
Check the running version right after you change a version file, not weeks later. A .node-version that the host quietly ignored looks identical to one that worked until you actually read process.version.
What was in the 2026 releases
Worth knowing so you can judge urgency rather than guessing at it.
October 21, 2026 fixed 10 CVEs, patched in v22.23.4, v24.22.1 and v26.12.1. Four are HIGH: two TLS certificate hostname bypasses (one of them hits only 24.x and 26.x), a dns.resolve truncation bug, and the one that matters most here, CVE-2026-111497 in the Brotli decoder.
The Brotli bug needs an attacker who "can supply Brotli data that an application decompresses with node:zlib." That can arrive in a request body or in a response your server fetches. The second path sounds rare until you look at what does the decompressing for you:
fetch()decodes Brotli responses even when it didn't ask for them. We tested this on Node 22.22.0:fetchsentaccept-encoding: gzip, deflate, the test server repliedcontent-encoding: branyway, andfetchdecoded the body without complaint. So the server on the other end decides, not you.- axios asks for Brotli outright. Its Node adapter (checked in axios 1.21.0) sends
brinAccept-Encodingand pipesbrresponses throughzlib.createBrotliDecompress. - Plain
node:httpdoes not decompress on its own. You only meet the decoder there if your code or a library adds it.
That makes the risky pattern any route that fetches a URL someone else controls: link previews, "import from URL" features, webhook senders you call back, scrapers, an AI agent tool that fetches pages. Vercel's WAF can't see those responses. On Vercel the patched runtime (or, during the rollout, the temporary mitigation) is what covers them, and both only reach you through a new deployment.
June 18, 2026 fixed 12 CVEs, patched in v22.23.0, v24.17.0 and v26.3.1. Two HIGH: a WebCrypto AES integer overflow causing denial of service, and a TLS wildcard-depth authentication bypass involving unicode dot separator handling.
July 29, 2026 fixed 11 CVEs, patched in v22.23.2, v24.18.1 and v26.5.1. Three HIGH:
CVE-2026-56848, a re-entrant send heap-use-after-free in HTTP/2.CVE-2026-56846, HTTP/2 retained headers bypassingmaxSessionMemorylimits.CVE-2026-58043, Permission Model path matching over-granting filesystem access, where a process granted one directory can reach outside it.
Severity here is about your exposure, not just the number. The HTTP/2 bugs need you to be terminating HTTP/2 in Node. If you sit behind a platform proxy that speaks HTTP/1.1 to your process, which is the common shape on Render and Railway, those two are much less interesting than the version number suggests. The Permission Model one only applies if you actually use --permission. Most vibe-coded apps don't.
What to do about it
If you're on Cloudflare Workers, nothing for Node's own CVEs. If you're on Vercel, redeploy after a security release, confirm process.version moved, and move any Node 20 project to 22.x or 24.x. That's the whole job.
If you're on any of the other four, the fix is one decision: pin the major version, not the exact one. Put 22 in .node-version instead of 22.23.0, then make sure something triggers a rebuild periodically. A dependency bump, a scheduled deploy, anything that runs the build again.
Find your current pin. Look for .node-version, .nvmrc, engines.node in package.json, a NODE_VERSION variable in your host dashboard, and a FROM node: line in a Dockerfile. More than one can exist, and they don't all have the same precedence on every host. The dashboard variable usually wins on Render; RAILPACK_NODE_VERSION wins on Railway.
Loosen an exact pin to a major. If you find 20.11.1, and you had no specific reason for those last two numbers, replace it with 20. If you did have a reason, write it in a comment so the next person doesn't loosen it blindly.
Redeploy and confirm. Read process.version from the running app, not the build log alone. Confirm it moved.
Stop broadcasting the version. A default Express app sends X-Powered-By: Express, and some setups leak runtime detail in the Server header. That doesn't create a vulnerability, but it turns "scan everything and see what sticks" into "scan the things already known to be behind." Our scanner flags these as information disclosure findings with the exact header value it saw, because they're one of the cheapest things to remove.
The honest summary: this is a ten-minute audit that most people never run, on a question their host's marketing page doesn't answer. The Netlify pinning behavior in particular is documented in one sentence, in a page about dependency management, which is not where anyone looks when they're wondering whether they need to patch.
Do I need to update Node.js on Vercel?
You don't change a version number, but you do need to redeploy. Vercel picks the patch version for 22.x and 24.x, and its docs say it rolls out patches when needed. After the October 21, 2026 release, though, Vercel's bulletin said only new deployments get the patched Node, and told existing projects to redeploy. Projects still on Node 20 must switch to 22.x or 24.x, because 20 is end of life and gets no fix.
Does Netlify update Node.js automatically?
No. Netlify pins your site to the default Node version of its build image, and the docs say your builds "won't change even if the build image's defaults change." The version moves only when you rebuild, and only if you specified a major version like 24 rather than an exact one like 20.11.1.
How do I check which Node version my deployed app is running?
Log process.version from a live route and read the response, or add node -v to your build command and read the deploy log. Don't trust your local node -v or the engines field. Those describe intent, not what the host actually booted.
Is an outdated Node runtime actually exploitable?
Depends which CVE and how you're deployed. Of the 11 fixed on July 29, 2026, three were HIGH: two HTTP/2 flaws including a heap-use-after-free, and a Permission Model path-matching bug. The HTTP/2 pair only bites if your Node process terminates HTTP/2 directly, which it often doesn't when a platform proxy sits in front of it.
Does pinning an exact Node version make me safer?
It makes you more reproducible and less patched. An exact pin like 22.23.0 means every future rebuild reinstalls that exact version, CVEs included. Pinning the major version lets each rebuild move forward to the latest patch on that line.
Your Node version is one input. What an attacker sees is the whole surface: leaked keys, missing headers, open endpoints, and the version banners your server volunteers. A CheckYourVibe scan checks your live app from the outside and tells you what's exposed right now.