Do I Need to Update Node.js on Vercel? Who Patches Your Runtime (2026)

Node.js shipped 23 CVE fixes across two security releases in 2026: twelve on June 18, eleven more on July 29. Three of the July ones are rated HIGH, including a heap-use-after-free in the HTTP/2 stack.

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 and Cloudflare patch the runtime under you, so there's nothing to do. 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.

  1. Does the runtime move on its own? If your host manages Node as infrastructure, patches land without a deploy.
  2. 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. So the answer to "do I need to update Node on Vercel" is no, and you couldn't pin an exact patch even if you wanted to.

Cloudflare Workers. Different reason, same outcome. 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

HostRuntime moves on its own?What a rebuild does
VercelYes, minors and patches roll automaticallyNothing extra needed
Cloudflare WorkersYes, Cloudflare patches workerdNo Node version to manage
NetlifyNo, pinned to build image defaultPicks up latest patch only if you set a major-only version
RenderNo, resolved per serviceSame, and the unset default tracks service creation date
RailwayNo, baked into the image at buildRe-resolves from your spec
Fly / DockerNo, frozen to the base image digestOnly if you re-pull the base tag

Read that middle column as the real question. Four of six rows say no.

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.

The only check that counts, from a live route
// 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.

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 bypassing maxSessionMemory limits.
  • 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 Vercel or Cloudflare, nothing. Genuinely nothing. Go do something else.

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.

1

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.

2

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.

3

Redeploy and confirm. Read process.version from the running app, not the build log alone. Confirm it moved.

4

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?

No. Vercel only exposes major versions, and its docs state that it "automatically rolls out minor and patch updates when needed, such as to fix a security issue." You choose 24.x, Vercel chooses which 24.x. The tradeoff is that you can't pin an exact patch version even if you have a reason to.

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.

How-To Guides

Do I Need to Update Node.js on Vercel? Who Patches Your Runtime (2026)