Patch management for PHP and Node.js went from quarterly to once every six months on October 21, 2026. On that date, PHP issued emergency patches to address two critical remote code execution vulnerabilities called PHP2Shell, and Node.js issued patches for ten CVEs, one of which involves a Brotli decoder flaw named Node2Shell.
Both of these vulnerabilities lie in the runtime layer, not in the code of your website. Even a website with all security updates installed in WordPress, Laravel, or Express framework may still be at risk, if the PHP or Node.js executable beneath them is out of date.
Below is an overview of what needs to be patched, how to minimize risks if a patch cannot be applied right away, and how to confirm that a fix was implemented. This article is intended for business owners as well as developers, agencies, and hosting providers managing websites.
What PHP2Shell and Node2Shell actually are
PHP2Shell refers to two vulnerabilities in PHP runtime environment: CVE-2026-109618 and CVE-2026-109619. Both have severity rating of 9.2 according to CVSS v4.0 standard and allow an unauthenticated attacker to execute remote code in a PHP-powered web server.
The first vulnerability is a memory-corruption exploit resulting from an out-of-memory error while processing requests. The second is use-after-free, where one request on a worker processes the data freed by a previous one. In addition, researchers managed to read the memory of live workers, which might contain passwords, session tokens, and API keys of other site visitors.
Node2Shell is CVE-2026-111497, a security flaw in the form of an out-of-bounds write in the Brotli decompression library bundled into Node.js. Every Node.js process using Brotli to decompress attacker-controlled data is vulnerable even if you do not invoke the Brotli library from your code explicitly.
| PHP2Shell | Node2Shell | |
| CVEs | CVE-2026-109618, CVE-2026-109619 | CVE-2026-111497 (plus nine other Node.js CVEs fixed the same day) |
| Severity | Critical, CVSS v4.0 9.2 | High (Node.js rating) |
| Where it lives | PHP core, every SAPI that serves web requests | Brotli decoder bundled in Node.js and Bun |
| How it is reached | A crafted HTTP request to any PHP page, even “Hello World” | Brotli request bodies (Express 5, body-parser 2.x), Brotli responses to fetch(), direct zlib calls |
| Highest-risk setups | Apache mod_php; PHP-FPM is also exploitable under some conditions | Internet-facing Express 5 APIs, webhook senders, scrapers, link-preview and AI agents that fetch URLs |
| Versions affected | Nearly every release back to PHP 5.4 | All supported lines before October 21, 2026, plus every end-of-life line |
| Activity as of Oct 22 to 23 | Mass scanning and exploit attempts; no confirmed break-in reported | Working exploit against the official 24.22.0 image in a lab; no in-the-wild use reported |
The attacks on the PHP2Shell exploits are genuine. For example, Cloudflare reported that within a day after disclosure, attack attempts increased from ten thousand to a million per minute. Sophos and Arctic Wolf noticed attempts to infect websites with Mirai botnet malware.
On October 23, PHP also identified CVE-2026-115560, a more limited session security hole, which is not fixed in the October 21 patches. It affects applications using session.serialize_handler dynamically and can be mitigated similarly to PHP2Shell (by disabling session.upload_progress).
Why runtime patches catch businesses out
The vast majority of website maintenance activities are performed at the next level up. You upgrade WordPress plugins, run composer update, and merge Dependabot Pull Requests. Your dashboard gets green.
This is all separate from the runtime. The PHP binary is provided by your server’s package manager, your hosting company, or your container base image. The Node.js binary is installed somewhere else and possibly many years ago.
Here are three facts about runtime patching that are often misinterpreted:
- A running process still uses the old code. If you have PHP-FPM worker processes, Apache running mod_php, or long-lived Node.js processes, the vulnerable code stays in memory until the next restart.
- The version number is misleading. Many Linux distributions backport security patches to software that looks like an older version number, and Node.js applied the Brotli patch without bumping process.versions.brotli.
- There is probably more than one On any server, there could be multiple versions of PHP 7.4 for one website and PHP 8.3 for another, and php -v does not necessarily show the PHP serving your web traffic.
Step 1: find every PHP and Node.js runtime you own
If it’s not on your list, then it cannot be fixed, and the list is always larger than you expect. First, start from web-facing servers, then proceed inside.
For PHP, investigate web servers, hosting control panels like cPanel or Plesk, container images, internal tools or appliances that include their own PHP packages. The only way to reliably find out the version of PHP used by a server is to check what web server actually uses, rather than the one shown in the shell.
# PHP from command line interface (may differ from web-facing PHP)
php -v
# PHP-FPM binaries and corresponding versions
ls /usr/sbin/php-fpm* 2>/dev/null; php-fpm -v 2>/dev/null
# Running PHP workers, with start time
ps -eo pid,lstart,args | grep -E ‘[p]hp-fpm|[a]pache2|[h]ttpd’
In Node.js context, examine the servers, CI runners, Docker images, and even development machines. The tools like nvm or Volta install executables in the user’s directory, and the PM2 or systemd service configuration may be different from the shell’s.
# All the node binaries on the PATH, with their versions
type -ap node | while read -r n; do echo “$n $(“$n” -v)”; done
# Node.js version inside container image
docker run –rm <image> node –version
# Running Node.js processes and their start time
ps -eo pid,lstart,args | grep -E ‘[n]ode( |$)’
Make note of owner, internet access, and patch location (package, host, image). One sheet of paper transforms the following two items from speculation into task list.
Step 2: patch PHP
According to the PHP team, updating PHP is the only full patch for PHP2Shell. The following is the sequence of patches based on the PHP advisory coverage:
| PHP branch | Vulnerable | First fixed version | Upstream support |
| 8.5 | below 8.5.12 | 8.5.12 | Supported |
| 8.4 | below 8.4.27 | 8.4.27 | Supported |
| 8.3 | below 8.3.36 | 8.3.36 | Supported |
| 8.2 | below 8.2.35 | 8.2.35 | Ends December 31, 2026 |
| 8.1 and older | All | No regular release | End of life |
First, patch internet-facing servers running Apache mod_php since PHP itself notes that one unauthenticated request is enough to execute an attack using PHP in the context of mod_php prior to application code execution. The second group of web servers is FPM, php-cgi, FrankenPHP and LiteSpeed, in which case the way FPM operates mitigates only one possible attack vector.
The actual order will be as follows:
- Patch the PHP package (apt, dnf, apk), check your host’s PHP version or rebuild your container from a patched image.
- In the case of distribution packages, validate that the package has been patched according to the CVE IDs and not the version number.
- Start up Apache, PHP-FPM and all long-lived PHP workers/queue runners/daemons.
- Check your memory_limit and post_max_size. With this fix, there is a strict memory limit, and a worker that hits it will be stopped immediately without calling any shutdown handlers.
Upgrading your WordPress, Laravel, Magento or Drupal installation will not help with PHP2Shell, you have to patch your PHP engine itself.
Step 3: patch Node.js
Node.js patched the PHP2Shell CVE and nine others on October 21st. Four of them are high severity: two CVEs for TLS hostname verification bypass and a CVE in dns.resolve(), so each of your services should be updated even if it doesn’t use brotli at all.
| Node.js line | Status | Fixed version |
| 26.x | Current (Active LTS from October 28, 2026) | 26.12.1 |
| 24.x | Maintenance LTS | 24.22.1 |
| 22.x | Maintenance LTS until April 30, 2027 | 22.23.4 |
| 25.x, 23.x, 20.x and older | End of life | No upstream fix |
| Bun | Supported | 1.4.4 |
Start with those services that have more exposure. Services with Internet-facing Express 5 APIs and those fetching URLs from unknown domains (webhooks, scrapers, URL previewers, AI bots fetching website data, self-hosted Next.js image optimization) should get updates first. You could wait one or two days for updating an Express 4 service communicating with your backends only.
- Move to version 22.23.4, 24.22.1 or 26.12.1, or later patch on the same line.
- Re-deploy container images. Any image that uses pinned Dockerfile with node:24.22.0 will continue to be vulnerable no matter how many times you re-build it, so it’s better to pin somewhere else.
- If the installation of Node.js was done through a distribution package, then it may have linked the system Brotli library instead of the built-in library. Use command ldd “$(command -v node)” | grep -i brotli and install the update for the distribution’s Brotli library.
- Restart all Node.js processes. Rebuild standalone executables and start-up snapshots using the patched runtime.
- Verify managed platforms. Managed services like Vercel could be behind the upstream releases and require projects that are running on Node.js 20 to update to 22 or 24 and re-deploy.
Stopgaps when you can’t patch today
The host may not have yet sent the package, or the older program may fail to run on the updated platform. These actions serve merely to provide some breathing room, and neither project denies that.
Settings should be made using php.ini file, FPM pool, or server configuration file, and then workers need to be restarted. All the settings made using ini_set() or .user.ini file will not work.
| Setting | What it blocks | Caveat |
| session.upload_progress.enabled=0 | Confirmed session paths for CVE-2026-109619 and CVE-2026-115560 | Does nothing for CVE-2026-109618 |
| fatal_error_backtraces=0 (PHP 8.5) | The confirmed mod_php backtrace path | PHP 8.5 only |
| memory_limit=-1 set by admin, low post_max_size, request size constraints at the proxy | The attacker-driven out-of-memory exploit in CVE-2026-109618 | Removes PHP’s per-request memory cap, so add container or cgroup limits |
| Prevent multipart requests for websites that do not receive any uploads | The documented multipart triggers | Breaks any upload form |
| pm.max_requests=1 (FPM) | State carried between requests on one worker | Real performance cost |
It is not recommended to apply RLIMIT_AS or RLIMIT_DATA as the memory limit as this PHP recommendation stated by Qualys shows that it may lead to taking a vulnerable route. A WAF policy may help; however, Cloudflare found out that hackers tried to bypass their own policies by changing payloads.
For Node.js, drop requests with Content-Encoding: br on the reverse proxy/load balancer and have inflate: false in body parsers that do not require body inflation. Neither applies to Brotli encoding used by your application to get a response, and there is no way to turn off fetch() decoding.
If a vital service cannot be patched or mitigated, then access should be limited to the general public until it can. Every non-patched system needs an owner and a deadline assigned.
Verify the fix and look for earlier break-ins
Patching ticket will be marked as complete when the running process uses the patched code, not upon package installation. Re-run the ps command from step 1 and verify that all the PHP and Node.js processes that started after patching have been accounted for.
There is one line for the presence of the fixed Brotli decoder in the upstream Node.js builds. It outputs true if binary is patched:
node -p “‘BROTLI_DECODER_ERROR_FORMAT_BLOCK_SWITCH’ in require(‘zlib’).constants”
This approach will work only for nodejs.org official binaries. In case of distribution or extended support builds refer to the vendor’s advisory since the script npx is-my-node-vulnerable performs version comparison and may misreport the patched build as vulnerable.
In PHP, verify the package to have been fixed based on the changelog and re-scan with vulnerability scanner. Do not launch any publicly available POC scripts against the production environment since according to Qualys, they could tie up the workers and cause attacker-generated memory corruption.
Should the target server have been left open while under attack, check the logs to determine if there is any evidence of a successful exploit. PHP2Shell authors recommend monitoring for:
- Unusual multipart requests preceded by memory limit errors and/or HTTP 500 response code explosions
- Unexpectedly huge PHPSESSID cookie values in response headers
- unexplained PHP worker restarts
- Any spawned shell or other child processes initiated from php-fpm, apache2 or httpd
Maintain a simple note for each affected machine: package name, advisory reference and indication of service restart. This is exactly what auditors and cyber insurance companies require.
The end-of-life problem
The problem is worst at the end-of-life runtimes. According to Qualys, 110 million out of the 156 million known PHP installs in their user base use PHP 5.4 to 8.1, which is no longer patched by the PHP project.
Node.js 20 will also face the same fate since Node.js 20 went EOL on April 30, 2026, and Node.js 18 went EOL a year earlier, meaning none will get the October upstream security fixes.
Here are three practical ways of dealing with an outdated runtime:
- Updating to a supported branch is the only sustainable way of addressing the problem even though the move from PHP 7.4 to 8.3 could break old themes, plugins, and extensions.
- Patched builds during transition is the second alternative since there were source-level backports from PHP for versions 7.4, 8.0 and 8.1, as well as extended support vendors such as TuxCare offering patched versions for EOL PHP and Node.js runtimes.
- Isolate the system used for authentication or a virtual private network if neither of the above methods can be performed this week.
Mark the date when PHP 8.2 goes out of support, which will happen by December 31, 2026, ten weeks since the PHP2Shell vulnerability release.
A patch routine that holds up next time
October 2026 demonstrated how short the period is. Node.js published a pre-warning on October 14, released it on October 21, and an exploit for the default installation appeared the very next day, while PHP gave only one day of warning once the details of the vulnerability were published.
Such a procedure does not have to be overly complex:
- Pay attention to the correct sources. Subscribe to the security updates for php.net, Node.js security releases blog, oss-security mailing list and to your Linux distro security notifications. UAE-based organizations should also monitor the security notifications issued by the UAE Cyber Security Council.
- Maintain an up-to-date inventory. Keep the inventory up to date every time a new site, server, or image is created, not yearly.
- Stick to supported Maintain a list of end-of-life dates for all runtimes, and plan migrations at least two quarters out.
- Rebuild images When base images are rebuilt weekly, a runtime fix will be available in containers without having a dedicated project.
- Schedule patches based on risk. For example, critical vulnerabilities in internet-facing systems get patched in 48 hours; all others within the normal cycle.
- Make the restart part of the patching process. Make sure that it is documented in runbooks to avoid closing tickets with old workers.
- Start with the staging A brief smoke test will detect either the memory-limit change in PHP or a native Node.js addon which will not load.
Choosing a PHP2Shell remediation service in Dubai
Many companies in the UAE use shared hosting environments, a reseller’s VPS environment, or a built-stack by some agency whose workings they do not understand in-house. Then, PHP2Shell remediation service will be faster for the moment then learning everything about the server under a live attack.
An effective engagement will cover the full process, not just package updates:
- listing all PHP and Node.js runtimes across your hosting, cloud, and container infrastructure
- updating or backporting all of them
- interim mitigations in case the fix needs to be delayed, deployed on the server side and validated
- rebooting workers and rebuilding images, validated against active processes
- a check of logs for any evidence of prior exploitation, such as web shells or abnormal child processes
- a report documenting what was patched, how it was validated, and what issues remain outstanding
Prior to engaging with anyone to address the issue, determine how they will validate the currently running PHP version for each site, how they will test without exploiting the sites, and what measures they will take if they find that there is evidence of a security breach.
In case your customers’ data might be exposed, consult with a lawyer in advance. Federal data protection laws in the UAE, as well as the DIFC and ADGM regulations regarding companies registered in these free zones, may imply a breach notification requirement.
FAQ
Does updating WordPress protect me from PHP2Shell?
Not applicable, since PHP2Shell lies in the PHP engine, and the only way to patch it is to patch the PHP runtime. WordPress, its plugins and themes lie above the runtime and cannot affect it.
Which PHP version should I be on?
At least version 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or a distribution package where the changelog includes CVE-2026-109618 and CVE-2026-109619. Given the end of support of version 8.2 in December 31, 2026, new projects should start at versions 8.4 or 8.5.
Is my Node.js site affected by Node2Shell if I use Express 4?
Express 4’s body-parser fails parsing Brotli request bodies, closing the inbound attack path. Nine remaining CVEs of October and the fetch() function call are still relevant, so update Express regardless.
Is turning off session upload progress enough?
Not applicable, since the patch blocks the confirmed session paths for CVE-2026-109619 and applies to CVE-2026-115560, but is irrelevant to CVE-2026-109618.
How do I know if my PHP host has patched?
Find out the specific version of PHP that is powering your website and what vulnerability it fixes. After that, get a phpinfo() page from your web server and remove it immediately.

