Skip to main content
Urgent

Node2shell, http2shell and PHP vulnerabilities: what to do

Three critical RCE bugs this week. For Node.js apps on DollarDeploy a redeploy is enough; Bun, Python and PHP need one extra step each.

— Ruslan Gainutdinov

Three critical remote code execution bugs went public this week. Each has a CVSS score of 9.2, and each can be exploited without logging in. If you run apps with DollarDeploy, here is what is affected and what to click.

TLDR For Next.js and other Node.js apps, a redeploy is enough. Bun apps need one extra env var before redeploying. Python apps need a lockfile bump. For PHP apps, run Prepare on the server, then redeploy. Docker Compose apps need fresh images. Deno and nginx need nothing.

Why it matters: your apps run on your own servers, so patching the runtime is on you. The good news: with DollarDeploy it is a few clicks, not an SSH session per server.

What happened

Node2Shell / HTTP2Shell (CVE-2026-111497)

A bug in Google's Brotli decoder (libbrotli 1.0.3 to 1.2.0) lets a crafted br compressed stream write past a buffer. It was first reported for Node.js (Node2Shell), then for Python packages, and is now called HTTP2Shell because almost anything that speaks HTTP bundles Brotli.

There are two ways in:

  • Inbound: your app decodes a request body sent with Content-Encoding: br.
  • Outbound: your app fetches a URL and the server answers with a Brotli response. Node's fetch(), Python requests/httpx/aiohttp (when Brotli is installed) and curl decode it automatically.
  • Most exposed: apps that fetch URLs users give them, like webhooks, link previews, crawlers and "call this URL" features.

The nginx in front of your apps is not the problem (details below). The runtime behind it is.

Fixed versions:

Runtime Fixed in
Node.js 22.23.4, 24.22.1, 26.12.1
Bun 1.4.4
Python Brotli 1.2.1
Python brotlicffi 1.2.1.0
libbrotli 1.2.1 (or 1.0.10 / 1.1.1)

Node.js 20 and older get no fix. Move to 22 or later.

PHP2Shell (CVE-2026-109618, CVE-2026-109619)

Two bugs in PHP itself, affecting PHP 5.4 to 8.5 on every web setup, including PHP-FPM. Exploitation attempts were seen before the patch was public. Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Ubuntu and Debian ship backported fixes for their own PHP packages, so the version number on your server may not change.

What to do in DollarDeploy

Next.js and other Node.js apps: redeploy

On every deploy, DollarDeploy runs nvm install for your app's Node major version (NODE_VERSION, default 22, or the one in .nvmrc). nvm always resolves a major version to its latest release, so a redeploy installs the patched Node and restarts the app on it.

  1. Open the app and click Deploy, or Deploy latest build from the dropdown.
  2. In the deploy log, check the line Installing node .... It should show 22.23.4, 24.22.1 or 26.12.1 or later.

One catch: if your .nvmrc or NODE_VERSION pins an exact version, like 24.19.0, the redeploy keeps it. Change it to 24 (or 24.22.1), push, and redeploy.

Bun apps: set BUN_VERSION, then redeploy

A redeploy does not upgrade Bun by itself. DollarDeploy installs Bun only when it is missing or when BUN_VERSION asks for a different version.

  1. In the app's environment, add BUN_VERSION=1.4.4.
  2. Redeploy. The deploy log shows Installing Bun 1.4.4.

If you ship a binary built with bun build --compile, it carries its own copy of Bun. Rebuild it after the upgrade.

Deno apps: nothing to do

Deno does not use Google's Brotli C library. Its fetch() and node:zlib decode Brotli with a Rust rewrite of the decoder, which returns an error on the crafted stream instead of writing past a buffer. Keep Deno current as usual: DollarDeploy installs the version from DENO_VERSION or your mise.toml.

Python apps: bump Brotli in the lockfile, then redeploy

Python apps install the exact versions in your lockfile, so a redeploy alone keeps the vulnerable package. Brotli often gets in as a dependency of a dependency, so check even if you never added it.

  • With uv: uv lock --upgrade-package brotli --upgrade-package brotlicffi, commit uv.lock, redeploy.
  • With requirements.txt: set Brotli>=1.2.1 (and brotlicffi>=1.2.1.0 if present), commit, redeploy.

To see why it is installed: pipdeptree -r -p Brotli. Most scanners (pip-audit, Dependabot) do not flag it yet.

PHP apps: Prepare the server, then redeploy

DollarDeploy PHP apps use the PHP-FPM package from Ubuntu or Debian, and the fix arrives as a regular system update.

  1. Open the server and click Prepare. It applies pending package upgrades and restarts services that still run the old binaries.
  2. Redeploy each PHP app, so its PHP-FPM process starts on the patched binary.
  3. Check in the server terminal: apt changelog php8.3-fpm | grep CVE-2026-109618 (use your PHP version). If nothing comes up, your distro has not shipped the fix yet. Run Prepare again once it has.

DollarDeploy also turns on unattended security upgrades on every server, so the package gets installed automatically within a day. The running PHP-FPM process still needs the redeploy to pick it up.

Docker Compose apps: pull or rebuild the images

The vulnerable runtime lives inside your images, and a plain redeploy reuses the images already on the server. What to do depends on where the image comes from.

  • Image from a registry (image: node:24, image: php:8.3-fpm): add DOCKER_COMPOSE_PULL=always to the app's environment and redeploy. Compose then pulls the newest image for that tag. This works for tags that move, like node:24. A pinned tag like node:24.19.0 never changes, so bump it in your compose file first.
  • Image built from your Dockerfile (build:): change the FROM line to a patched version, for example node:24.22.1-slim, oven/bun:1.4.4 or php:8.3.36-fpm. Add DOCKER_COMPOSE_BUILD=1 to the app's environment so the redeploy rebuilds the image, then push and redeploy.
  • Python inside a container: bump Brotli in the lockfile the same way as for Python apps above.

Check the result in the server terminal: docker compose exec <service> node -v (or php -v, bun --version).

Nginx: nothing to do

DollarDeploy installs nginx from the official nginx.org packages, without the Brotli module. It compresses responses with gzip only and never decodes Brotli, so nginx itself is not affected. Prepare keeps it updated anyway.

Nginx does pass request bodies to your app unchanged, including ones sent with Content-Encoding: br. If your app decodes them (Express 5 does by default), the fix is the Node.js upgrade above, not nginx.

Yes, but: HTTP2Shell is still unfolding. Brotli copies bundled inside other software (.NET, PHP and Ruby extensions, databases like ClickHouse and DuckDB) are not all patched yet. The steps above cover the runtimes DollarDeploy installs. For anything else on your server, follow that vendor's advisory.

Check a server in one go

In the server terminal in DollarDeploy, or over SSH:

# Node.js versions installed for apps (/app or /home/<user>)
ls -d /app/.nvm/versions/node/* /home/*/.nvm/versions/node/* 2>/dev/null

# Bun versions installed for apps
for b in /app/.bun/bin/bun /home/*/.bun/bin/bun; do [ -x "$b" ] && echo "$b $($b --version)"; done

# System Brotli and PHP packages
dpkg -l | grep -E "libbrotli|php[0-9.]+-fpm"

Anything below the fixed versions above needs the steps for its app type. An old Node version still listed is fine as long as the deploy log shows the app now runs on the patched one. If you get stuck, ask on Discord or email hello@dollardeploy.com and we will look at your server with you.

Sources

Updated on Oct 24, 2026