Skip to content
Book a Consultation

PHP and Node.js Vulnerabilities 2026: What Happened and How to Fix It

Masum Shamjad · 22 October 2026 · 16 min read

PHP and Node.js Vulnerabilities 2026: What Happened and How to Fix It

On 21 October 2026, PHP and Node.js both shipped emergency security updates. The PHP flaws, nicknamed PHP2Shell, can let an attacker run their own code on a web server without logging in. The Node.js flaw sits in its Brotli decompression code and can also lead to remote code execution.

If your website, web app or API runs on either technology, update now:

  • PHP: fixed in 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Update, then restart every PHP worker.
  • Node.js: fixed in 22.23.4, 24.22.1 and 26.12.1. Update, then restart every Node.js process.
  • Older versions: PHP 8.1 and earlier get no upstream fix, and Node.js 20, 25 and older lines got no fix in this release. Upgrade to a supported line, or for PHP use a vendor-backed extended-support build.

W3Techs figures cited by Tenable put PHP behind roughly 7 in 10 websites whose server-side language is known, and it powers WordPress, Drupal and Joomla. That reach is why the UK's National Cyber Security Centre (NCSC) told organisations to update straight away, or take affected systems offline if they cannot. Below, we explain what went wrong in plain terms and how to fix it.

What went wrong in PHP: PHP2Shell explained

PHP2Shell is a pair of critical memory-safety bugs in the core PHP engine, tracked as CVE-2026-109618 and CVE-2026-109619. The PHP security team rated both 9.2 out of 10 (CVSS v4.0); a score of 10.0 that circulated before release was wrong. Both bugs are set off by errors that strike at the wrong moment and leave PHP's memory in a broken state.

In plain terms:

  • CVE-2026-109618, half-built request data. If a request hits PHP's memory limit while PHP is still setting that request up, PHP stops part-way. Its clean-up step then treats the half-built data as valid, which corrupts memory and can open a route to running code.
  • CVE-2026-109619, leftovers from the last request. A fatal error at the wrong point can leave PHP's internal state pointing at memory that belonged to an earlier request. When the same worker process handles the next request, it can use that freed memory. This can leak server memory, such as passwords, API keys and tokens, and can be turned into code execution.

How much an attacker needs depends on how PHP is run. On Apache with mod_php, a single unauthenticated request can trigger CVE-2026-109618 before any application code runs, and full remote code execution was shown with default settings. On PHP-FPM, code execution was confirmed through paths in application code (PHP Foundation). Separately, Wiz showed unauthenticated code execution against default WordPress, Drupal and Joomla container images, and traces the bugs back to PHP 5.4.

PHP says every installation that serves web requests is at risk, including PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed, with mod_php the most exposed. Researchers at Calif, OpenAI and Wiz reported the bugs separately, and Wiz says AI models helped its team find them. The PHP Foundation says AI now helps it validate reports and group duplicates, but a person makes every call and works on every patch.

How it unfolded

DateWhat happened
2024A developer funded by the PHP Foundation spotted early signs of the out-of-memory problem while fixing an issue from an external audit by Quarkslab. No practical attack was found at the time.
30 July 2026Calif began an audit of PHP through the Patch the Planet programme.
11 August 2026A Calif researcher reported working remote code execution caused by the out-of-memory bug. OpenAI reported the same root cause that day.
24 August 2026Wiz reported its findings to the PHP security team.
18 September 2026OpenAI reported further attack routes.
17 October 2026Amazon's honeypots logged the first known exploitation attempt, four days before disclosure.
20 October 2026, about 15:00 UTCThe two CVE numbers leaked online with a wrong release time and a wrong score of 10.0, but no technical details.
20 October 2026, 19:30 to 20:00 UTCPHP published its pre-announcement early. Around 20:00 UTC, Calif mistakenly published a video of its proof of concept.
21 October 2026, 07:41 UTCChainguard broke the embargo by publishing container images with the fix, more than six hours before the coordinated release.
21 October 2026, 14:00 UTCPHP released 8.5.12, 8.4.27, 8.3.36 and 8.2.35, a day earlier than planned.

What went wrong in Node.js: the Brotli decoder flaw

The most serious Node.js issue, CVE-2026-111497, is an out-of-bounds write in the copy of Google's Brotli library that ships inside Node.js. Brotli is a compression format used across the web alongside gzip. Feed the decoder specially crafted compressed data and it can write outside the memory it should, which Node.js says can permit remote code execution.

It is one of 10 fixes in the 21 October release, four of them rated High. The others include two TLS certificate hostname-check bypasses and a DNS name-truncation bug, so the update matters even if your code never touches Brotli.

This is a serious bug, but not every Node.js server is equally exposed. Your app is at risk when it decompresses Brotli data that someone else controls, which happens more often than teams expect:

  • Incoming request bodies. Express 5 apps decompress Brotli request bodies when body-parser 2.x middleware, such as express.json() or express.raw(), is in use (Imperva). A bare Node.js HTTP server does not decode incoming Brotli bodies on its own.
  • Outgoing calls. The built-in fetch() decodes Brotli responses, and Imperva reached the vulnerable decoder this way. A call to a malicious or compromised server can trigger the bug.
  • Direct use. Code that passes untrusted data to the Brotli functions in node:zlib (The Hacker News).

An app that only compresses its own responses is not decompressing untrusted input. Patch it anyway, because the TLS and DNS fixes in the same release reach well beyond Brotli.

Who is affected, and is it being exploited?

PHP2Shell is the more urgent of the two: it is rated Critical and attackers were probing for it before the fix existed. The Node.js flaw is rated High, and no attacks had been reported as of 22 October 2026.

PHP (PHP2Shell)Node.js (Brotli flaw)
CVECVE-2026-109618, CVE-2026-109619CVE-2026-111497 (plus 9 other fixes)
SeverityCritical, CVSS v4.0 9.2High
AffectedVersions up to 8.5.11; Wiz traces the bugs back to PHP 5.422.x, 24.x and 26.x before the fix, and all end-of-life lines
Fixed in8.5.12, 8.4.27, 8.3.36, 8.2.3522.23.4, 24.22.1, 26.12.1
No upstream fix8.1 and earlier20.x, 25.x and older
Attacks (22 October 2026)Millions of attempts, no confirmed breachNone reported

PHP: treat it as actively targeted

As of 22 October 2026, attack attempts are widespread but no successful breach has been confirmed. Cloudflare reported millions of attempts against sites it protects, and Amazon logged the first attempt on 17 October, four days before disclosure.

Germany's BSI and the US CISA said they had seen no successful exploitation, and as of 21 October neither CVE was in CISA's Known Exploited Vulnerabilities catalog (The Hacker News). Treat unpatched, internet-facing PHP servers as targets regardless.

Estimates of exposed servers depend on how they are counted. Tenable puts potentially vulnerable internet-facing hosts at 1.3 to 1.9 million, while VirusTotal data reported by BleepingComputer counts over 5.1 million exposed PHP hosts. PHP also hides inside products you may not think of as PHP: hosting control panels, network appliances and vendor software.

Node.js: no attacks yet, but code execution reproduced

Imperva reproduced code execution against an official Node.js 24.22.0 image in tests published on 22 October, but reported no attacks in the wild. Vercel's firewall rules block the inbound attack for projects it hosts, but do not cover Brotli responses your code fetches from other servers (The Hacker News). Imperva has also added firewall rules for the attempts it reproduced.

Who needs to act

  • Anyone running WordPress, Drupal, Joomla, Laravel or another PHP app on their own server, VPS or container.
  • Shared hosting customers: ask your host which PHP build your site runs and when it was patched.
  • Teams running Node.js APIs, Express apps, or services that fetch data from other servers.
  • Users of managed platforms: Google App Engine standard (PHP 8.2+) patches automatically, but App Engine flexible, Cloud Run without automatic base image updates, and your own container images all need a rebuild and redeploy.

How to fix PHP2Shell

Updating PHP is the only complete fix. Workarounds lower the risk but do not close the hole.

  1. Find every PHP install. Start with internet-facing servers, then check staging sites, old microsites, hosting control panels and vendor appliances. Check the version your web server uses, not just the command line, as the two can differ: run php-fpm -v (or php-fpm8.3 -v), or in WordPress open Tools, then Site Health, then Info, then Server.
  2. Update to a fixed release. Use PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35. On Debian, Ubuntu, Red Hat and similar systems, install your distribution's security update instead. Vendors often backport the fix without changing the version number, so check the package changelog for the CVE rather than the number alone.
  3. Restart every PHP worker. Restart PHP-FPM, Apache or LiteSpeed so no process keeps running the old code. For containers, rebuild the image with patched PHP and redeploy.
  4. Review your memory settings. The fix adds a new hard memory limit: a request that reaches it ends the worker process and skips shutdown handlers. Check memory_limit and post_max_size against what your application needs, and undo any memory_limit=-1 stopgap (The Hacker News).
  5. Deal with end-of-life versions. PHP 8.1 and earlier get no upstream fix. If you cannot upgrade yet, use your distribution's backported package or a vendor-backed extended-support build such as TuxCare's Endless Lifecycle Support, which is rolling out fixed builds for 8.1 and older. The lasting fix is a supported release, and as PHP 8.2 reaches end of life on 31 December 2026, aim for 8.3 or newer.
  6. Check for signs of compromise. On any server that was exposed and unpatched, look for new or changed files in the web root, unfamiliar cron jobs, new user accounts, and PHP processes launching shells or tools such as curl and wget. Bursts of HTTP 500 errors and memory-limit errors after upload requests are another warning sign.

If you cannot patch today

The PHP project published temporary mitigations. Restart all PHP workers after any change.

  • For CVE-2026-109619: set session.upload_progress.enabled=0 and restart every PHP worker. On PHP 8.5, also set fatal_error_backtraces=0. PHP says this was never a complete fix, and it does not address CVE-2026-109618.
  • For CVE-2026-109618: set memory_limit=-1 in a way applications cannot override (for example php_admin_value in the FPM pool), and pair it with a container or cgroup memory cap. Keep post_max_size as low as your application allows: check your current value against what your forms and uploads need, and cap request sizes at the web server or proxy. Do not use RLIMIT_AS or RLIMIT_DATA instead, as PHP warns they can trigger the same vulnerable path.
  • Add a web application firewall. Cloudflare deployed rules for known attack patterns, including on its free plan, but describes them as a stopgap.
  • Take it offline if you must. If none of this is possible quickly, the NCSC advises taking the system offline until it is fixed.

Hiding errors with display_errors or error_reporting does not help. On Debian or Ubuntu servers, the upload-progress change can go in a small drop-in file for each PHP version you run:

# Set this to your PHP version, for example 8.2, 8.3, 8.4 or 8.5
V=8.3

# PHP-FPM
echo 'session.upload_progress.enabled=0' | sudo tee /etc/php/$V/fpm/conf.d/99-php2shell-mitigation.ini
sudo systemctl restart php$V-fpm

# Apache with mod_php (skip if you only use PHP-FPM)
echo 'session.upload_progress.enabled=0' | sudo tee /etc/php/$V/apache2/conf.d/99-php2shell-mitigation.ini
sudo systemctl restart apache2

# PHP 8.5 only: add the second setting to the same file, then restart again
# echo 'fatal_error_backtraces=0' | sudo tee -a /etc/php/$V/fpm/conf.d/99-php2shell-mitigation.ini

# Confirm PHP-FPM picked it up: the value should show Off
php-fpm$V -i | grep session.upload_progress.enabled

Command-line PHP (php -i) reads its own settings file, so a result there does not prove your website is covered. Check the FPM or Apache setting itself. On shared hosting, change the setting in your control panel's PHP options or ask your host to apply it.

Our suggestion: confirm the fix by CVE, not by version number

Debian and Ubuntu packages often carry the fix under an older-looking version number, so search the package changelog for the CVE instead. If the command prints a line, the fix is installed:

apt changelog php8.3-fpm | grep -m1 CVE-2026-109618

Change php8.3-fpm to your package name. Rather not run PHP servers at all? Move a marketing site to a hosted platform such as Webflow or Wix, or book a 30-minute call with us.

How to fix the Node.js flaw

Upgrading Node.js is the only fix. The official advisory offers no workaround inside Node itself.

  1. Check your version. Run node -v. You are covered on v22.23.4, v24.22.1, v26.12.1 or later in the same line. Run which -a node to spot a second install on the same machine, and check the version inside every container image. Desktop apps built on Electron ship their own runtime and need their vendor's update.
  2. Update the Node.js runtime itself. With nvm, run nvm install 24 and set it as the default; with NodeSource or other packages, upgrade the nodejs package. Official Node.js binaries and Docker images bundle their own Brotli decoder, so updating the system libbrotli package does not fix them. It only helps Node.js builds that link against the system library.
  3. Rebuild containers. Run docker pull node:24 (or your base tag) before rebuilding, so images pick up the patched base. A pinned tag such as node:24.22.0 stays vulnerable, so move the pin to 24.22.1 or later.
  4. Restart every process. A running process keeps the old binary in memory, so restart pm2, systemd services and containers after updating.
  5. Move off unsupported lines. This release fixed only 22.x, 24.x and 26.x (Node.js advisory). Move Node.js 20 and older to 22 or 24, and Node.js 25 to 24 or 26.

Two mistakes to avoid

  • Do not switch off TLS checks if connections start failing after the update. Setting rejectUnauthorized: false or NODE_TLS_REJECT_UNAUTHORIZED=0 removes the protection this release adds. Fix the certificate or hostname instead.
  • Do not rely on npm audit to catch this. It checks your packages, not the Node.js runtime.

If you cannot update today

Imperva suggests temporarily limiting untrusted Brotli traffic on affected paths, after testing against normal traffic. For incoming requests, one way is to refuse Brotli-encoded request bodies at an nginx reverse proxy:

# Temporary: reject Brotli-compressed request bodies until Node.js is patched
if ($http_content_encoding ~* br) {
    return 415;
}

This covers incoming requests only. Outgoing calls that decode Brotli responses stay exposed until you update.

Our suggestion: check Node.js inside every running container

Updating the host does not update your containers. This prints the Node.js version inside each running container; anything below v22.23.4, v24.22.1 or v26.12.1 in its line still needs a rebuild:

for c in $(docker ps -q); do echo "$(docker inspect -f '{{.Name}}' $c): $(docker exec $c node -v 2>/dev/null)"; done

Rather not manage runtimes yourself? A managed platform such as Vercel, Netlify or Cloud Run updates them for you, a marketing site can move to Webflow or Wix, or book a 30-minute call with us.

How PHP itself is getting safer

The PHP Foundation funded several engineers to work full time on the PHP2Shell fix, including weekends, and is changing how PHP handles security:

  • A dedicated security team. The Foundation formed an Ecosystem Security Team in May 2026 to work with PHP's security team on triage, coordination and hardening. Its people include Volker Dusch, AI Security Engineer in Residence; Alexandre Daubois, who joined in July 2026 to handle security reports; and Daniel Scherzer, who joined in September 2026 for hardening work.
  • Faster decisions. The security team is moving to majority decisions and will bring in Foundation leadership sooner when a fix stalls over trade-offs.
  • More eyes on the code. External audits by Quarkslab, Calif and Trail of Bits, plus AI-assisted scanning, are feeding in reports. Since 1 July 2026, the team has published 15 CVEs and worked through more than 100 invalid, duplicate or non-reproducible reports.

The Foundation is asking the companies, hosting providers, cloud platforms, distributions and governments that rely on PHP to sponsor this work. For everyone else, the takeaway is practical: more audits mean more security releases, so the speed of your own patching matters more than ever.

Beyond the patch: six habits that make the next one faster

Two major runtimes needed emergency updates on the same day. The update itself takes minutes; finding every place that needs it is often the slow part. These habits shorten that search next time.

  • Keep a live inventory. List every server, container and hosted service with its runtime and version, including vendor appliances and old campaign sites.
  • Stay on supported versions. End-of-life runtimes, such as PHP 8.1 and Node.js 20, get no fix when the next critical bug lands.
  • Rebuild images on a schedule. Turn on automatic base image updates where your platform offers them, and rebuild containers regularly, not only when something breaks.
  • Watch your web workers. Alert when a PHP or Node.js process launches a shell, a scripting language or a download tool such as curl or wget.
  • Follow the right sources. Subscribe to the PHP and Node.js security announcements and your hosting provider's bulletins. UK organisations can also sign up to the NCSC's free Early Warning service.
  • Rehearse the emergency patch. Know who can approve, test and deploy an urgent update out of hours, and how long that takes.

Need a hand with the update?

TulipTech's Managed IT & Cloud Infrastructure and Cyber Security teams look after servers and applications for clients every day, including the 45+ virtual machines we manage for WTV. If you are not sure where PHP or Node.js runs in your estate, or you are stuck on an end-of-life version, we can help you:

  • find every affected server, container and hosted service;
  • patch, rebuild and restart with downtime planned and kept short;
  • check exposed systems for signs of compromise;
  • plan the move off PHP 8.1 or Node.js 20.

TulipTech is ISO 27001 and Cyber Essentials certified, headquartered in Leicester, est. 2011.

Book a free IT risk review. We reply within one business day, from a real person, not a bot.

Frequently asked questions

What is PHP2Shell?

PHP2Shell is the name for two critical bugs in the core PHP engine, CVE-2026-109618 and CVE-2026-109619, patched on 21 October 2026. They let an attacker who is not logged in corrupt or read server memory using ordinary upload requests. In some set-ups, that leads to running code on the server.

Is my WordPress site affected?

Yes, if it runs on an unpatched PHP version, because the flaw is in PHP itself rather than in WordPress or its plugins. Updating WordPress or plugins does not fix it. Check Tools, Site Health, Info, Server for your PHP version, and ask your host to confirm the build was patched on or after 21 October 2026.

Which PHP versions are safe?

PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, and later releases in those lines, are fixed. Packages from Debian, Ubuntu, Red Hat and other vendors may carry the fix under an older version number, so check the package changelog for the CVE. PHP 8.1 and earlier get no upstream fix: upgrade, or use a vendor-backed extended-support build such as TuxCare's.

Is turning off session upload progress enough?

No. PHP says turning off session upload progress was never a complete fix: it blocks a known route to CVE-2026-109619 but does not fix CVE-2026-109618. Treat it as a stopgap for the hours before you patch, not as the fix.

Which Node.js versions are safe?

Node.js 22.23.4, 24.22.1 and 26.12.1, and later releases in those lines, are fixed. Node.js 20 and older, and Node.js 25, got no fix in this release, so move them to a supported line.

Is a web application firewall enough?

No. Firewall rules from providers such as Cloudflare, Vercel and Imperva block known attack patterns and buy time, but Cloudflare calls its rules a stopgap and has seen attackers change payloads to get around them. Vercel's Node.js rules also do not cover responses your code fetches from other servers, so updating remains the only complete fix.

We use managed hosting. Do we need to do anything?

Confirm with your provider rather than assuming you are covered. Some platforms, such as Google App Engine standard on PHP 8.2 or newer, patch automatically. Others only pick up the fix when you rebuild and redeploy, and anything on an end-of-life version stays vulnerable.