Security Approximate reading time: 11 min ·

Node.js Security Update: Is Your Version Still Receiving Fixes?

On 21 October Node.js published security patches for the 22, 24 and 26 release lines. Which versions are safe, why Node.js 18 and 20 will not receive a security patch, and how to check which version your application is using.

A browser window with a gear and a confirmation mark — a Node.js security update

On 21 October Node.js published security patches for the 22, 24 and 26 release lines. Which versions are safe, why Node.js 18 and 20 will not receive a security patch, and how to check which version your application is using.

Only the release lines that still have support received a security patch, and the safe versions are 22.23.4, 24.22.1 and 26.12.1, or anything newer on the same release line. Node.js 18 and 20 have already reached end of life, so this Node.js security update contains no security patch for them and never will: if your application is running on either of them, updating means moving to a different release line.

On Wednesday 21 October the Node.js project published security releases for all three supported release lines, and on the same day PHP published emergency security patches for the vulnerabilities that were given the name PHP2Shell, but these are two separate events, and they are not of the same severity. The Node.js release had been announced in advance, the project has rated its most serious vulnerabilities as high rather than critical, and the announcement mentions neither a workaround nor any attack observed in the real world. That does not let you put the update off, but it does move where the attention belongs: this time the greatest risk is not in the release itself, but in the versions that did not receive it.

What the October Node.js security update fixed

The Node.js announcement lists ten vulnerabilities: the project has rated four of them high, three medium and three low, but it has not published Common Vulnerability Scoring System (CVSS) scores this time, so this article uses that same rating.

The most serious of them is CVE-2026-111497. The project calls it an out-of-bounds write in the Brotli decoder that permits remote code execution (RCE), and it rates the vulnerability high. Brotli is a compression format whose decoder is built into Node.js, and in the release notes the security patch is described as a change in that built-in library. The announcement does not say by which path the vulnerability can be reached, and the Brotli developers' description of the fix speaks only of an invalid data stream now being recognised earlier. That is why no specific functions are named here: the only thing it is safe to say is that a flaw in the decoder matters most to applications which decompress Brotli data from a source they cannot trust.

Three other vulnerabilities affect the checking of TLS certificates, and they are not one and the same case. The first, rated high, affects only the 26 and 24 lines: hostname verification can be bypassed when an IP address is written with fullwidth digits, for example 127.0.0.1. The second, also high, affects all three lines: the check can be bypassed when the hostname can be loosely read as an IP address. The third is medium, and it too affects all three lines: a non-standard IPv4 notation lets a DNS name given in the certificate vouch for an IP address. In the release notes the fixes are put briefly: IP addresses written in an unusual form are now rejected, and a regression in IP-address normalisation has been fixed separately. In all three cases what is at issue is the moment when Node.js is acting as a client, that is, when it itself opens an encrypted connection to another server, and not the moment when it is serving its own visitors.

The fourth vulnerability rated high is in the dns.resolve function, which truncated names that contain a null character. Among those rated medium is a bug in the reuse of HTTP connections, in which a response written on the connection before the request was sent could be handled as the response to that request, and a bug because of which the randomness cache of crypto.randomUUID() and randomInt() was saved into startup snapshots and into a single executable application (SEA), so that every process repeated the same values; three vulnerabilities rated low affect the handling of ZIP files and the Node.js permission model.

The bug in the randomness cache is worth understanding precisely, because in the ordinary case it affects nothing at all. It applies only to projects that start from a startup snapshot they have built themselves, or that are distributed as a single executable application (SEA), and there it means that every process started from the same file received the same "random" values. If a project of that kind used crypto.randomUUID() or randomInt() to build identifiers or temporary codes, those values could repeat from one process to another, so after the security patch it is worth checking whether any of them is used somewhere it has to be unguessable.

The release also updates several built-in dependencies, depending on the release line: c-ares, OpenSSL, SQLite and Undici, which the built-in fetch function rests on. The CA store, the bundled list of trusted certificate authorities, has likewise been updated because of a compromised eMudhra intermediate certificate, and TLS connections now reject chains that contain blocked public keys.

Which versions are safe

The patched versions are three, one for each supported release line: 22.23.4, 24.22.1 and 26.12.1. Everything older on its own line is affected. Not all ten vulnerabilities affect every line: the 26 line has all ten, the 24 line has eight, and the 22 line has seven, because two bugs rated low exist only on the newest line and one TLS bug does not affect the 22 line.

Updating within the release line is the smallest step there is, and it is usually also the safest change that can be made in production. Even that step can change behaviour, though, and this time there is a concrete example: the fix to the TLS check now rejects IP addresses written in an unusual form. If an application once used such a form in its connections to another server, the connection can fail after the update. That is a security hole which has been fixed, not a new bug, but it is worth knowing before the update rather than afterwards.

The release line matters more than the version number

Up to Node.js 26 every major version goes through one cycle: first it is the Current release, then the even-numbered versions receive active long-term support (Active LTS), then they move into the Maintenance LTS phase, in which they receive only critical bug fixes and security patches, and at the end support stops altogether, whereas odd-numbered versions up to the 25 line did not receive long-term support at all. From Node.js 27 the cycle changes: according to the release schedule every line will receive long-term support, and for all 30 months of that support it will stay in the active phase, with no Maintenance LTS phase, and the project itself writes that production applications should only use Active LTS or Maintenance LTS releases.

For the lines now in use, the nearest changes of phase fall on two dates: according to the Node.js release schedule the 24 line moved into the Maintenance LTS phase on 20 October, the day before the security release, and the 26 line will receive long-term support on 28 October. The 22 line has been in the Maintenance LTS phase since 21 October 2025 and will reach end of life on 30 April 2027, while the 24 line will reach end of life on 30 April 2028.

The practical point is a simple one: the question "do we have the latest version" does not, by itself, say very much, whereas the useful question is "which release line are we on, and until which date will it receive security patches". The first question changes its answer every month, and the second changes once every couple of years, which is exactly why the second is easy to forget.

Node.js 18 and 20: there will be no security patch

The Node.js announcement contains a sentence that, this time, matters more than all ten vulnerabilities: versions that have reached end of life are always affected when a security release occurs. No security patch is released for them, either now or later, because a release line that has reached end of life no longer receives any release at all.

According to the release schedule the 16 line reached end of life on 11 September 2023, the 19 line on 1 June 2023, the 18 line on 30 April 2025 and the 20 line on 30 April 2026. The last of those dates is the one that matters most: the 20 line reached end of life a little under six months ago, and a project that was started on it can still be running without any problem that you can see. That is exactly what makes the situation deceptive, because nothing in the way it runs shows that security patches are no longer due to it.

For companies that cannot move quickly onto a supported line, the Node.js announcement mentions one option: commercial support for versions past the Maintenance LTS phase is offered by the partners of the OpenJS Ecosystem Sustainability Program. It is a paid service, and it is a temporary arrangement, not a substitute for making the move.

How to check which Node.js your application uses

The check takes minutes, but there is one place where it is easy to do wrong: the Node.js version the terminal shows is not always the version the application is actually running on.

Hosting with cPanel: The version in use is shown under Software → Setup Node.js App, where each application has its own row and the version is chosen from a list. The list contains only those versions that the hosting provider has installed on the server. The command node -v on hosting of this kind can show a different version from that setting, so look at the row for the application itself.

Your own server: The command node -v shows the version that comes first on the system path, but a process manager, for example PM2 or a systemd service, can start the program with an entirely different executable. The answer you can trust is the one the process reports about itself: the value of process.version, for example written to the log at the moment it starts.

Containers: In a Docker environment the version is set by the container image, not by the host machine. A container image built before 21 October does not contain the security patch, however many times the container has been restarted, so the container image has to be rebuilt from an updated base image.

If you have no access: Then the question goes to the hosting provider, or to the developer who maintains the application. A wording that saves a round of correspondence: "Which Node.js version does our application use? On its own release line, is it at least 22.23.4, 24.22.1 or 26.12.1? If it is on a line that has reached end of life, for example 18 or 20, when is the move planned?"

What to do today

Today's order is this: first update Node.js to the patched version on its own line and restart every process that uses it, then rebuild everything in which the runtime is built in, and only after that plan the move for those projects that are running on lines past end of life.

First, update within the release line, to 22.23.4, 24.22.1 or 26.12.1, depending on which line you are on. Where the application is on hosting, the provider does this, and your job is to make sure that the application is using the version that has been updated.

Second, restart the processes: A process that is already running keeps using the Node.js it was started with, and replacing the file on disk does not affect it. The same was true of PHP2Shell: the package has been replaced, but the old process keeps running the old code.

Third, rebuild whatever has the runtime built in: Docker container images have to be rebuilt from an updated base image. If you distribute the program as a single executable application (SEA), Node.js itself is built into that file, so updating the version installed on the system does not affect it, and the file has to be built again with the patched version. The same applies to startup snapshots, which are affected by the bug in the randomness cache.

Fourth, if you are on the 18 or 20 line, plan the move: That is a larger piece of work than an update within the line, so it is worth starting now, and the order is set out in the next section.

How to move off Node.js 18 or 20

A move between major versions is not the work of a single command, and it is worth doing in sequence, with the target chosen first. In most cases that target is the 24 line, which will receive security patches until 30 April 2028; the 22 line is a sensible choice only when some important dependency does not yet support the 24 line, because support for the 22 line ends a year earlier.

Then every place where the project sets its own Node.js version has to be found, because there are almost always several of them: the engines field of package.json, the files .nvmrc or .node-version, the base image in the Dockerfile, the configuration of the continuous integration (CI) environment, and the setting in the hosting panel. If only some of those places are changed, different environments run different versions, and the errors show up in the place where they are hardest to find.

After that the project has to be installed afresh in a test environment, on the new version, and the tests have to be run. Particular attention is due to packages that contain compiled code: they are built for one specific Node.js version, so after the move they may have to be rebuilt or updated. For each major version Node.js publishes a list of changes, and the changes that can break existing code are marked out separately in it, which is worth reading before the move rather than after it.

Only then does production come: the change of version, the restart of the processes, and a check that process.version shows the new version. The old version can stay available for a few days, in case you have to go back, but not for longer than that, because that is exactly the version for which there will be no further security patch.

What is not updated together with Node.js

Updating Node.js repairs the runtime itself and the libraries that are built into it, but not everything the application uses, and this is exactly where the holes that nobody sees are most often left behind.

Packages installed separately: If the project uses the undici package from npm among its dependencies, rather than the built-in fetch, that package sits in the project's node_modules directory, and a Node.js release does not touch it. The same is true of every other dependency: the package manager is what updates them, and only when someone actually runs it.

The CA store: By default Node.js does not use the operating system's list of certificate authorities, but its own built-in CA store, and the documentation says that this is a snapshot of the Mozilla list, fixed at the moment of the release. A change such as this release's response to the compromised eMudhra intermediate certificate therefore reaches the program only together with the runtime update, and not together with the operating system's updates, unless the program has been specifically configured to use the system list.

How not to miss the next release

Node.js announces its security releases in advance, on its security page, and it names the day the release is planned for, which is exactly what happened this time. This Wednesday was therefore no surprise to anyone who watches that page: the update could be put in the diary beforehand, rather than a free hour being hunted for on the day itself.

In practice that means someone has to be responsible for the watching: on managed hosting the provider does it, but on your own server, or on a project that your own team maintains, it is worth knowing who follows the project's announcements, who decides that the update will be made, and who checks that everything still works once it has been. If the answer to those questions is "nobody in particular", that is where the greatest risk sits, and not in any one of the ten vulnerabilities.

If Node.js is only a build tool for you

On many Laravel and WordPress websites Node.js does not run on the server at all: it runs Vite, or a similar build tool, which prepares the CSS and JavaScript files from the source code and then stops. In that case the situation differs from an application that serves requests itself, because the build process does not answer requests from the internet and does not decompress data sent to it by visitors it does not know.

That it differs does not mean it does not matter: build tools run on developers' computers and in the continuous integration environment, they download packages, and they open connections to other servers, and the descriptions of the vulnerabilities are too short for anyone to say with confidence which of those paths are affected. Updating Node.js is worth doing there as well, only in the right order: first the servers where Node.js is running live, and after that the developers' computers and the continuous integration environment.

There is a second reason as well, and it has nothing to do with this week: a build environment often stays on the Node.js version the project was once started with, and then one day a new version of a tool simply refuses to work with it. The move onto a supported line then happens in a hurry, and at a moment that does not suit, so it is easier to do the move now, while it is still planned work.

What this meant on our hosting

Our managed hosting is space on our own server, and each client there chooses a version through the hosting panel. On our server the Node.js 22 and 24 lines are already running the patched versions, 22.23.4 and 24.22.1. For clients whose projects use these lines, nothing has to be done, except making sure that the process has been restarted after the update.

The other side has to be said plainly as well: lines that have reached end of life are still available to choose on the server, and there is no security patch for them — not on our server, and not on anyone else's, because Node.js does not release one. If one of those lines has been chosen for your project, updating means moving to the 22 or 24 line, and that move is best made together with a check that, afterwards, everything works as it did before.

Our managed hosting starts at €45 a month, and maintained runtimes are part of what that sum pays for. If your application is still running on Node.js 18 or 20, let us talk through the move before the day of some later security release forces it to be done.

FAQ

Frequently asked questions.

Which Node.js version is safe?

The safe versions are 22.23.4, 24.22.1 and 26.12.1, or any newer version on the same release line. Everything older on its own release line is affected. For a version whose release line has reached end of life, for example Node.js 18 or 20, there is no safe version at all, because no security patch is released for it.

I have Node.js 18 or 20. What should I do?

Both release lines have reached end of life: the 18 line on 30 April 2025, and the 20 line on 30 April 2026. There is no security patch for them, and there will not be one, so the only way through is a move to a supported release line. The 24 line will receive security patches until 30 April 2028, and the 22 line until 30 April 2027. The move is worth trying in a test environment first.

Is this Node.js security update the same thing as PHP2Shell?

No. Both events fell on 21 October, but they are separate. PHP2Shell was two critical vulnerabilities in PHP itself. The Node.js security release had been announced in advance, its most serious vulnerabilities are rated high, and the announcement does not mention attacks in the real world.

Is updating Node.js enough if the application is already running?

No. The process has to be restarted. A process that is already running keeps using the Node.js it was started with. If the application is inside a Docker container image, or is distributed as a single executable application (SEA), Node.js itself is built into it, and it has to be rebuilt with the patched version.

Our Laravel or WordPress website uses Node.js only to build with Vite. Does this affect us?

Less than it affects an application that serves requests itself, because the build process does not answer requests from the internet. Build tools do download packages and open connections to other servers, though, so Node.js is worth updating on the developers' computers and in the continuous integration environment as well, and only after the servers.

Are there workarounds if we cannot update straight away?

The Node.js announcement does not mention any workaround. The only recommendation is to use a supported version, following the release schedule. For versions that have reached end of life, Node.js mentions commercial support offered by the partners of the OpenJS Ecosystem Sustainability Program.

How do I see which Node.js version an application uses on cPanel hosting?

Under Software → Setup Node.js App, where each application has its own row showing the version that was chosen. The command node -v in the terminal can show a different version from the application's setting, so look at the application's own row.

RELATED SERVICE
Managed hosting and servers

Servers, hosting and maintenance in the EU — Frankfurt, Helsinki or Riga, with 24/7 monitoring. Full management: updates, security and performance, automated backups with tested restores, SSL certificates, CDN and DDoS protection. We migrate you from your current host with no downtime and scale with the load.

Learn more