Introduction
A serious security vulnerability known as Node2Shell (CVE-2026-111497) was disclosed on October 21, 2026, affecting the Node.js runtime.
The vulnerability exists in the Brotli decompression implementation bundled with Node.js. Under certain conditions, an attacker can supply specially crafted compressed data that causes memory corruption in a Node.js application.
Successful exploitation can potentially result in:
- Remote code execution (RCE).
- Process memory disclosure.
- Application crashes and denial of service.
- Compromise of the server process running the vulnerable application.
The vulnerability is particularly important for production servers hosting Node.js applications, REST APIs, microservices, and applications using HTTP request-body decompression.
The Node.js project has released security updates addressing this vulnerability. Administrators should update affected installations and restart all applications using the vulnerable runtime.
This guide explains how to identify affected Node.js installations, update Node.js using NVM or APT, and ensure PM2 and systemd services use the updated runtime.
1. Understanding the Node2Shell Vulnerability
Node2Shell is an out-of-bounds write vulnerability in the Brotli decoder used by Node.js.
Brotli is a compression algorithm commonly used for HTTP responses and request bodies.
Node.js provides Brotli decompression functionality through its built-in node:zlib module.
The vulnerability occurs when the decoder encounters a malformed Brotli stream containing an invalid block-type transition.
Instead of correctly identifying the input as permanently invalid, the vulnerable decoder incorrectly treats the condition as a request for additional input.
This causes the decoder to continue appending data to an internal buffer beyond its allocated boundary.
An attacker who can supply malicious Brotli-compressed data to an application that processes untrusted compressed content may trigger memory corruption.
Depending on the application and execution environment, this can potentially lead to remote code execution.
Where can applications be exposed?
Applications may encounter malicious Brotli data through several paths:
- HTTP request bodies with
Content-Encoding: br. - Express 5 applications using request-body parsing middleware.
- Applications using
zlib.brotliDecompress(). - Applications using streaming Brotli decompression.
- Node.js applications consuming compressed responses from untrusted external services through APIs such as
fetch().
An important point is that an application does not necessarily need to call the Brotli API directly to be exposed. Middleware and HTTP libraries may perform decompression internally.
Severity: Node.js classifies this vulnerability as High severity. The CVSS v4.0 score is 9.2.
2. Affected and Patched Node.js Versions
The Node.js security team released fixes on October 21, 2026.
The affected release branches and their initial fixed versions are:
| Node.js Branch | Initial Fixed Version |
|---|---|
| Node.js 26.x | 26.12.1 |
| Node.js 24.x | 24.22.1 |
| Node.js 22.x | 22.23.4 |
| Node.js 25.x | No upstream security fix |
| Node.js 20.x | No upstream security fix |
| Older versions | No upstream security fix |
Subsequent releases have also been published.
As of November 6, 2026, the following releases are available:
| Branch | Updated Version |
|---|---|
| Node.js 26.x | 26.13.0 |
| Node.js 24.x | 24.22.2 |
| Node.js 22.x | 22.23.4 |
For production servers, use the latest available security-maintained release in your chosen supported branch rather than stopping at the minimum fixed version.
Node.js 20.x and older unsupported branches should be migrated to a supported release line.
Important: A patched Node.js runtime does not automatically update every application or container on the server. Each deployment must be checked independently.
3. Identify the Installed Node.js Version
Before updating Node.js, determine how it was installed.
Linux servers commonly use one of the following installation methods:
- NVM (Node Version Manager).
- APT packages from Debian, Ubuntu, or NodeSource.
- Official Node.js binary installations.
- Docker containers with bundled Node.js runtimes.
Start by checking the current Node.js version:
node -v
npm -v
Identify the executable location:
which node
which npm
Check the resolved binary:
readlink -f "$(which node)"
Check the Node.js installation path:
node -p "process.execPath"
These commands help identify whether Node.js is running from a system directory or an NVM-managed directory.
Check whether NVM is installed
command -v nvm
If the command returns nothing, NVM may not be loaded in the current shell.
Check common NVM installation locations:
ls -la ~/.nvm
Check the NVM-managed versions:
ls ~/.nvm/versions/node/
If NVM is available:
nvm list
Check whether Node.js was installed using APT
dpkg -l | grep nodejs
Check the installed package version:
dpkg-query -W nodejs
Check the APT package source:
apt-cache policy nodejs
This is particularly important because different Linux distributions and repositories package Node.js differently.
4. Update Node.js Using NVM
NVM is commonly used when Node.js applications run under dedicated Linux users.
For example, a hosting server may have separate application users:
hellodocclinovanodeapp
Each user may have an independent NVM installation and Node.js version.
Updating Node.js under one user does not update installations belonging to other users.
Step 1: Switch to the application user
For example:
sudo -iu nodeapp
Check the current Node.js version:
node -v
Check NVM:
nvm --version
Step 2: Install a patched Node.js version
For Node.js 24:
nvm install 24.22.2
For Node.js 26:
nvm install 26.13.0
For Node.js 22:
nvm install 22.23.4
These commands install the specified versions under the current user’s NVM directory.
Step 3: Set the default Node.js version
For example:
nvm alias default 24.22.2
Activate it:
nvm use 24.22.2
Verify:
node -v
npm -v
which node
Expected Node.js version:
v24.22.2
The executable should point to the NVM installation directory.
For example:
/home/nodeapp/.nvm/versions/node/v24.22.2/bin/node
Step 4: Update PM2
If PM2 is installed globally under the same NVM-managed Node.js installation, update it:
npm install -g pm2@latest
Check the PM2 version:
pm2 -v
Refresh the PM2 daemon:
pm2 update
This updates the running PM2 daemon using the currently selected PM2 installation.
Step 5: Restart existing applications
Check existing PM2 applications:
pm2 list
Restart all applications:
pm2 restart all
Or restart an individual application:
pm2 restart application-name
Check the application logs:
pm2 logs --lines 100
At this stage, applications should be running with the updated Node.js runtime, provided they were started using the updated NVM environment.
However, there is another important consideration: systemd may still be configured to use the old Node.js installation path.
We will address this in Section 6.
5. Update Node.js Using APT
Some Linux servers use system-wide Node.js installations managed through APT.
This is common when Node.js is installed using:
- Debian repositories.
- Ubuntu repositories.
- NodeSource repositories.
First, refresh the package lists:
sudo apt update
Check the installed version:
node -v
Check the available candidate:
apt-cache policy nodejs
If the configured repository provides a patched version, upgrade Node.js:
sudo apt install --only-upgrade nodejs
Alternatively, upgrade the relevant installed system packages:
sudo apt upgrade
Important: Check the Brotli system library
There is an important distinction between official Node.js binaries and distribution-packaged Node.js.
Official Node.js binaries generally include their own Brotli implementation.
Some Linux distribution packages instead use the system Brotli library.
In the latter case, the distribution may deliver the security fix through its Brotli package rather than through a Node.js version update.
Check the installed Brotli package:
dpkg -l | grep brotli
Check its available version:
apt-cache policy libbrotli1
If the distribution provides a security update, install it:
sudo apt install --only-upgrade libbrotli1
Do not assume that upgrading libbrotli1 fixes every Node.js installation. It will not replace a vulnerable Brotli implementation bundled directly into a Node.js binary.
Likewise, do not assume that every Node.js package with an older upstream version is vulnerable. Distribution vendors can backport security fixes.
Always consult the appropriate Debian or Ubuntu security advisory.
Verify the installed package
node -v
npm -v
dpkg-query -W nodejs libbrotli1
Check the package’s security status against the relevant distribution advisory.
6. PM2 and systemd: An Important Post-Update Consideration
Updating Node.js is only part of the process.
Production Node.js applications frequently run under PM2, with systemd configured to start PM2 automatically when the server boots.
This introduces a potential problem when Node.js is installed using NVM.
The systemd service may continue pointing to the old Node.js installation even after NVM has been updated.
For example, the old installation might be:
/home/nodeapp/.nvm/versions/node/v24.22.0/bin/node
After upgrading:
/home/nodeapp/.nvm/versions/node/v24.22.2/bin/node
However, the existing PM2 systemd service may still contain the previous path.
If the old Node.js installation is removed or becomes unavailable, PM2 may fail to start after a server reboot.
This is why systemd configuration must also be reviewed after an NVM upgrade.
Step 1: Identify the PM2 systemd service
Run:
systemctl list-units --type=service | grep pm2
For an application user named nodeapp, the service is generally:
pm2-nodeapp.service
Check its status:
sudo systemctl status pm2-nodeapp
Step 2: Inspect the systemd service configuration
Run:
sudo systemctl cat pm2-nodeapp
You may see something similar to:
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target
[Service]
Type=forking
User=nodeapp
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/home/nodeapp/.nvm/versions/node/v24.22.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/nodeapp/.pm2
PIDFile=/home/nodeapp/.pm2/pm2.pid
ExecStart=/home/nodeapp/.nvm/versions/node/v24.22.0/bin/pm2 resurrect
ExecReload=/home/nodeapp/.nvm/versions/node/v24.22.0/bin/pm2 reload all
ExecStop=/home/nodeapp/.nvm/versions/node/v24.22.0/bin/pm2 kill
[Install]
WantedBy=multi-user.target
Notice that the service explicitly references Node.js 24.22.0.
After updating Node.js to 24.22.2, this path may no longer be correct.
Step 3: Regenerate the PM2 startup configuration
The recommended approach is to regenerate the PM2 startup configuration using the updated Node.js installation.
Switch to the application user:
sudo -iu nodeapp
Confirm that the updated version is active:
node -v
Run:
pm2 unstartup
Then generate the startup configuration again:
pm2 startup
PM2 will display a command that needs to be executed with sudo privileges.
It will look similar to:
sudo env PATH=$PATH:/home/nodeapp/.nvm/versions/node/v24.22.2/bin \
pm2 startup systemd -u nodeapp --hp /home/nodeapp
Execute the exact command generated by PM2.
This recreates the startup configuration using the current Node.js and PM2 installation paths.
Important: Do not blindly copy the example command. Use the command generated on your server because the NVM directory, Node.js version, and application username may differ.
Step 4: Save the PM2 process list
Before relying on automatic startup, save the current application process list:
pm2 save
This creates or updates:
/home/nodeapp/.pm2/dump.pm2
PM2 uses this saved process list when restoring applications during startup.
Step 5: Reload systemd
Run:
sudo systemctl daemon-reload
Enable the PM2 service:
sudo systemctl enable pm2-nodeapp
Restart it:
sudo systemctl restart pm2-nodeapp
Check the service:
sudo systemctl status pm2-nodeapp --no-pager
Inspect the startup configuration again:
sudo systemctl cat pm2-nodeapp
Confirm that the old Node.js version path has been replaced.
7. Verify PM2 Applications Are Using the Updated Node.js Version
Even if PM2 itself has been updated, it is important to verify the runtime used by individual applications.
First, list the applications:
pm2 list
Inspect an application:
pm2 describe application-name
Check the Node.js executable used by the running application:
PID=$(pm2 pid application-name)
readlink -f "/proc/$PID/exe"
For example, the expected executable should point to:
/home/nodeapp/.nvm/versions/node/v24.22.2/bin/node
You can also inspect running Node.js processes:
ps -eo user,pid,cmd | grep '[n]ode'
Check the application logs:
pm2 logs application-name --lines 100
Verify that the application is responding correctly through its configured domain or API endpoint.
8. Test PM2 and systemd Startup After Reboot
One of the most important steps is verifying that applications survive a server reboot.
Before rebooting, make sure you have:
- A working SSH session.
- A saved PM2 process list.
- An enabled systemd service.
- A verified application startup configuration.
- A recent backup.
Check the PM2 service:
sudo systemctl is-enabled pm2-nodeapp
Expected:
enabled
Check the service status:
sudo systemctl is-active pm2-nodeapp
Expected:
active
After a planned reboot:
sudo reboot
Reconnect to the server and check:
sudo systemctl status pm2-nodeapp --no-pager
Check PM2 applications:
sudo -iu nodeapp pm2 list
Check the Node.js version:
sudo -iu nodeapp node -v
Check the running executable:
PID=$(sudo -iu nodeapp pm2 pid application-name)
sudo readlink -f "/proc/$PID/exe"
The application should be running using the patched Node.js runtime.
9. Additional Security Recommendations
Updating Node.js should be part of a broader server security maintenance process.
Consider the following recommendations:
1. Avoid unsupported Node.js versions
Do not continue running applications on Node.js 20.x or older unsupported release branches without an appropriate vendor security-maintenance arrangement.
Plan application migrations to supported Node.js releases.
2. Keep PM2 updated
PM2 is responsible for managing production Node.js processes. Keep it updated and ensure its startup configuration is valid.
3. Restrict application access
Use firewall rules and reverse proxies to expose only the necessary application ports.
Avoid exposing internal application ports directly to the public internet.
4. Review request-body handling
Review Express middleware and other HTTP libraries that automatically decompress incoming request bodies.
5. Keep dependencies updated
Regularly review npm dependencies:
npm audit
Remember that npm audit checks application dependencies. It does not establish whether the installed Node.js runtime is patched.
6. Monitor application logs
Review PM2 logs and systemd journal entries for unexpected crashes, errors, or unusual application behaviour.
7. Maintain backups
Back up application configurations, PM2 ecosystem files, environment variables, and important application data before performing production updates.
8. Review Docker deployments
If Node.js is running inside containers, update the container base image and rebuild the application image.
Updating the host’s Node.js installation does not update Node.js inside an existing container.
Conclusion
Node2Shell (CVE-2026-111497) demonstrates why keeping the Node.js runtime updated is just as important as maintaining application dependencies.
For Linux administrators, updating Node.js is not always as simple as installing a new version.
Production environments frequently use NVM, PM2, and systemd together. If the Node.js runtime is upgraded without updating the associated PM2 startup configuration, applications may continue using an outdated runtime or fail to start after a reboot.
A proper security update should therefore include:
- Identifying every Node.js installation.
- Installing a patched runtime using NVM or APT.
- Updating PM2.
- Regenerating systemd startup configuration when required.
- Restarting applications.
- Verifying the actual runtime used by running processes.
- Testing application recovery after reboot.
Following these steps helps maintain a secure and reliable Node.js hosting environment.
Official security references
- Node.js Security Releases — October 21, 2026.
- Node.js Release Schedule.
- Node.js Official Release Downloads.
- PM2 Startup Documentation.
- NVM Documentation.
- Debian Security Tracker.
- Ubuntu Security Notices.
Always check the latest security advisories and distribution-specific package information before declaring a production server fully patched.
