Tutorial

Node.js CVE-2026-111497 (Brotli): update to 22.23.4

Security & Monitoring10 min read12 steps

On 21 October 2026, Node.js released versions 22.23.4, 24.22.1 and 26.12.1 to fix CVE-2026-111497, an out-of-bounds write in the Brotli decoder that can lead to remote code execution. On a fleet of sites running Next, Nuxt or Express, "just update" is not a full answer: you need to know which applications actually decompress untrusted Brotli, which processes still run the old binary, and what to do with an application stuck on Node 20. This guide gives the commands to inventory, fix and verify, then to reduce the risk when the fix has to wait.

Contents· What the October 2026 Node.js release fixes1/12
  1. 01What the October 2026 Node.js release fixes
  2. 02Affected versions and fixed versions
  3. 03Are you exposed: the deciding criterion
  4. 04Where untrusted Brotli can enter a Node application
  5. 05Inventory your fleet in fifteen minutes
  6. 06In which order to handle the fleet
  7. 07Update according to the installation method
  8. 08A process already running keeps the old Node
  9. 09If updating is impossible today
  10. 10Do not fix only the Brotli flaw
  11. 11For an agency: one fix per line, not per site
  12. 12The official documentation

What the October 2026 Node.js release fixes

On 21 October 2026, Node.js published updates for the 22.x, 24.x and 26.x lines. Among the ten vulnerabilities fixed, the project rates CVE-2026-111497 as High: the bundled Brotli decoder writes past an internal buffer when it receives malformed data. Concretely, an invalid block switch was reported as a mere need for more input rather than a permanent format error. The streaming decoder then kept appending bytes to an eight-byte internal buffer. The possible consequences range from a process crash to memory disclosure and remote code execution with the privileges of the Node process.

On severity, two readings coexist. Node.js says High; Google, as CVE numbering authority, assigns a CVSS v4 score of 9.2, according to Rapid7's analysis. As of 26 October 2026, Rapid7 is not aware of any exploitation in the wild, and the flaw is not in the CISA Known Exploited Vulnerabilities catalog. The flaw is therefore not exploited so far, according to Rapid7: this is a window to patch calmly, not a reason to wait.

Affected versions and fixed versions

Scroll the table

CaseStatusAction
Node.js 22.xAffected before 22.23.4Move to 22.23.4
Node.js 24.xAffected before 24.22.1Move to 24.22.1
Node.js 26.xAffected before 26.12.1Move to 26.12.1
Node.js 20.x and other end-of-life linesTreat as affected, no fix availableMigrate to 22.x or 24.x
Docker image node:<line>Affected until the image is rebuiltRebuild with --pull --no-cache
Node binary bundled in a tool (Electron, packaged executable)Depends on the embedded versionUpdate the tool itself
Other software that embeds the same Brotli decoderDepends on the vendorRead its own advisory

Are you exposed: the deciding criterion

Running a vulnerable Node is not enough to be attackable. The Node.js advisory targets an application that decompresses attacker-supplied Brotli data with node:zlib, through zlib.createBrotliDecompress or zlib.brotliDecompress. Rapid7 points out that the mere presence of the decoder does not establish exposure: everything depends on what the application decompresses. Do not conclude too quickly that there is no risk, though, because Brotli often goes through libraries you did not write.

The link with the Content-Encoding: br header is our reading, not a statement from the advisory. In the public source code, the fetch built into Node (undici) decodes br responses with zlib.createBrotliDecompress, the axios HTTP adapter provides the same decoding, and the current body-parser code does the same for incoming request bodies. Two flows therefore need review: what your application receives from clients, and what it fetches from third-party servers. You can check this in your own dependency tree, with the inventory commands below.

Where untrusted Brotli can enter a Node application

  • Compressed incoming requests — an Express API or a custom server that uses body-parser decompresses a Content-Encoding: br body sent by any client.
  • Responses from third-party services — fetch or axios calling an API, an RSS feed, a webhook or a page to preview: the remote server chooses the encoding of the response.
  • Server-side rendering — a Next or Nuxt application that fetches remote data during rendering goes through those same outgoing calls.
  • Proxies and gateways written in Node — a component that decompresses to inspect or transform content in transit opens both flows at once.
  • File processing — a service that accepts Brotli-compressed files or archives and opens them with zlib.brotliDecompress.
  • Build and CI tooling — deployment scripts and jobs that download artifacts: less exposed, but they use the same binary and get patched at the same time.
  • No path identified — lower priority, not zero: a dependency added later is enough to create exposure, and the release also fixes other flaws.

Inventory your fleet in fifteen minutes

  1. Read the version on each machine

    node -v
    which -a node
    Several binaries often coexist: the system one, the nvm one, one inside a container. which -a lists them all, and the first is not always the one the service uses.

  2. Find the real binary of each process

    ps -eo pid,user,args | grep -E '[n]ode|[p]m2'
    sudo readlink -f /proc/<pid>/exe
    The second command, run with the PID you found, gives the exact path of the binary running the process. It is the only reliable answer on a machine that carries several Node installations.

  3. Query the containers

    docker ps
    docker exec <conteneur> node -v
    docker images | grep node
    A running container does not fix itself: it keeps the image it started with, even if a newer image exists on the machine.

  4. Search your code for direct calls

    grep -rEn "createBrotliDecompress|brotliDecompress" --include=*.js --include=*.mjs --include=*.ts . --exclude-dir=node_modules
    Each line found is a point where your code decompresses Brotli. Look at where the data comes from: a file you produced yourself carries a different risk than a request body.

  5. Search for libraries that decompress on your behalf

    grep -rlE "createBrotliDecompress" node_modules --include=*.js
    npm ls body-parser axios undici
    The first command lists installed packages that call the decoder; the second shows which versions of body-parser, axios and undici are present in the project. Run them in every repository, not only the most recent one.

  6. Spot bundled binaries

    Tools that ship their own Node (Electron applications, packaged executables) are not covered by apt. Look up their version in their documentation and check whether the vendor has released a fixed version.

  7. Record the result in a table

    One row per process: machine, client, Node line, version, Brotli path identified or not. This table decides the order of work, and it will serve as proof once the update is done.

In which order to handle the fleet

A fleet of client sites with mixed versions and installations cannot be updated in one move, and it does not need to be. Start with the Internet-facing servers that receive compressed bodies or call third-party services: server-side rendering, gateways, proxies, public APIs. Internal applications and workers come next, then build tooling. Applications on Node 20 are a separate case: no fix will ever exist for them, and the only way out is migrating to 22.x or 24.x, which is better planned with the client than improvised. Work in stages of a few machines, and verify each stage before moving to the next.

Update according to the installation method

  1. apt package (NodeSource repository or distribution)

    apt-cache policy nodejs
    sudo apt-get update
    sudo apt-get install --only-upgrade nodejs
    node -v
    First read the source displayed by apt-cache policy: the repository must point to the right line (node_22.x or node_24.x). A repository left on an end-of-life line will never offer the fix. A distribution package may also carry a different number: compare with your distribution's advisory.

  2. nvm

    nvm install --reinstall-packages-from=current 22
    nvm alias default 22
    nvm use 22
    node -v
    The command installs the latest 22.x available; check that node -v shows 22.23.4 or higher. Do the same with 24 if that is your line. Services started by another user have their own nvm.

  3. Docker

    Change the tag on the FROM line, for example FROM node:22 or FROM node:24 with the variant you already use, then:
    docker build --pull --no-cache -t monapp:corrige .
    docker compose up -d
    The --pull option fetches the latest base image, --no-cache avoids reusing a layer built with the old Node. The running container is only replaced at redeployment.

  4. pm2

    pm2 restart all
    pm2 update
    After the binary is replaced, pm2 restart relaunches the applications; pm2 update refreshes the pm2 daemon in memory. The pm2 documentation adds that after a Node upgrade you should also refresh the startup script:
    pm2 unstartup
    pm2 startup
    pm2 save

  5. systemd service or another supervisor

    sudo systemctl restart <service>
    Restart each service one at a time, checking its log and health route before moving to the next. For an application behind a load balancer, take the machine out of the pool during the restart.

A process already running keeps the old Node

Replacing the binary does not fix running processes: they keep the old version in memory until they restart. A correct node -v on the machine therefore proves nothing about a service started yesterday. After each restart, verify from the process itself: pm2 jlist or pm2 show <nom> for the Node version in use, or process.version exposed in your health route.

If updating is impossible today

Node.js has published no workaround: the only vendor mitigation is the fixed version. Failing that, Rapid7 recommends restricting or disabling the application paths that decompress untrusted Brotli. Here is what that looks like in practice. The following points are risk-reduction measures we suggest, not vendor recommendations, and none replaces the fix.

On incoming requests, refuse Brotli at the reverse proxy level, for example in nginx: if ($http_content_encoding ~* br) { return 415; }. Test with nginx -t before reloading, and check that none of your legitimate clients sends br bodies. For responses from third parties, advertise only the useful encodings with the Accept-Encoding: gzip header, and limit the destinations your outgoing calls may reach. That last measure is partial: a malicious server can answer with br even if it was not requested, and the decoder follows the response header. On Vercel, WAF rules block the inbound flow but not the responses your functions fetch; redeploying with a fixed version is still necessary.

Do not fix only the Brotli flaw

The same release fixes nine other flaws. They include two high-severity TLS hostname verification bypasses, CVE-2026-105483 and CVE-2026-106069, as well as CVE-2026-105482, a truncation of hostnames containing a NUL character in DNS resolution, also rated High. They do not all affect the same lines: CVE-2026-105483 concerns the 26.x and 24.x lines, while the other two also concern 22.x. An application that validates TLS certificates for its outgoing calls therefore has good reasons to move to the fixed version without waiting to settle the Brotli question.

For an agency: one fix per line, not per site

When you carry dozens of sites, the update command takes a minute; the time goes elsewhere. You have to find which machine runs which version for which client, then obtain a restart window. Keep a living register, fed by the inventory above: at the next flaw, a simple filter on the Node line gives the list of sites to handle. The fewer variants in the fleet, the fewer cases to handle by hand, and reseller hosting follows that logic: a single interface for the portfolio and grouped renewals, whereas a collection of disparate servers multiplies the accesses to track. Applications stuck on Node 20 need separate handling: the migration guide linked below this article spares you from discovering the absence of a fix on the day of the next flaw.

The official documentation

Node.js security advisory of October 2026: https://nodejs.org/en/blog/vulnerability/october-2026-security-releases

Rapid7 analysis of CVE-2026-111497: https://www.rapid7.com/blog/post/etr-cve-2026-111497-critical-out-of-bounds-write-in-the-node-js-brotli-decoder/

Vercel bulletin: https://vercel.com/kb/bulletin/node-js-security-advisory

zlib module documentation: https://nodejs.org/api/zlib.html

nvm documentation: https://github.com/nvm-sh/nvm

Updating pm2: https://pm2.keymetrics.io/docs/usage/update-pm2/

docker build options: https://docs.docker.com/reference/cli/docker/buildx/build/

A fleet of sites to patch, without losing the night

A portfolio of sites is easier to run from one place. With ServOrbit.com reseller hosting, you follow accounts and renewals in a single interface, without multiplying the servers to watch.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab