PHP2Shell: how to check and protect your PHP site
PHP2Shell (CVE-2026-109618 and CVE-2026-109619): how to check your PHP version, patch it or shield it with a WAF, with two real cases.


On 20 October 2026, details of PHP2Shell (CVE-2026-109618 and CVE-2026-109619), two critical PHP remote code execution flaws, leaked online before a fix existed. Within 48 hours, Techdome had assessed and protected two client platforms: a US healthcare EMR system and a Saudi Arabia-based business application.
The two cases needed very different answers. One could be patched the same day. The other ran on a PHP version that will never receive a fix, so we put a shield in front of it while the upgrade is planned. This post explains what we did, and why, so other teams can move just as fast. It also works as a checklist you can run against your own PHP sites today.
What is PHP2Shell?
PHP2Shell is the name given to CVE-2026-109618 and CVE-2026-109619, two flaws in the PHP engine rated 9.2 out of 10. They let an attacker run their own code on a web server without logging in.
The flaws sit in the step where PHP reads an incoming request, before any application code runs. That is why passwords, two-factor login and access controls offer no protection: the attack lands before the login page is even processed.
- Who is affected: almost every PHP website, whatever framework it uses.
- The fix: PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, released on 21 October 2026.
- The catch: older versions such as PHP 7.x will never get an official fix.
- The urgency: attacks were reported on 21 October, hours before the patch shipped.
CVE-2026-109618 covers an upload-progress use-after-free that can leak server memory or run code. CVE-2026-109619 covers a fatal-error backtrace use-after-free and an OPcache type confusion. Both are rated CVSS 9.2.
Client 1: a US healthcare EMR platform
This platform was patched at the source: we updated PHP in its Docker image and redeployed.
What we found
The platform holds patient records, so a remote-code flaw here meant a possible data breach, not just downtime. A quick, non-intrusive check of the site's response headers showed it was running an outdated PHP 8.3 build, older than the fixed 8.3.36.
What we did
- Confirmed the exact PHP version in production without sending any attack traffic.
- Updated the PHP base image in the application's Dockerfile to a patched 8.3 release.
- Rebuilt and redeployed the containers, then confirmed the new version was live.
Why it worked
Because the app ran in containers, the fix was a one-line change to the base image rather than a server rebuild. A small, minor-version update within the same PHP branch meant no application code had to change. Rolling back, if anything had gone wrong, would have been equally simple: point the image tag back and redeploy.
Client 2: a Saudi Arabia-based business platform
This platform could not simply be patched, so we shielded it at the edge with Cloudflare while a full upgrade is prepared.
What we found
A read-only review of the server showed the application running PHP 7.2, which reached end of life in 2020 and gets no PHP2Shell fix. Scanning the codebase against PHP 8.3 found 47 files that would fail outright, plus email and Excel features that would break. Upgrading safely needs code changes and testing, which takes days, not hours.
What we did
- Deployed Cloudflare's managed WAF ruleset and set all seven PHP2Shell rules ("Generic Rules - Anomalous Execution 1 to 7") to Block.
- Confirmed each rule by its published Cloudflare rule ID.
- Wrote a step-by-step upgrade plan to PHP 8.3 covering every code change, testing and rollback.
Why this approach
A WAF filters malicious requests before they reach the server, buying time for a careful upgrade instead of a rushed one. It is a stopgap, not a cure: attackers are already varying their payloads, so the PHP upgrade remains the real fix.
What we learned
The speed of the response depended less on the vulnerability than on how each platform was built and maintained.
| Client 1 (US EMR) | Client 2 (Saudi platform) | |
|---|---|---|
| PHP version | 8.3, a few releases behind | 7.2, end of life since 2020 |
| Deployment | Docker containers | Single server, Apache mod_php |
| Fix available | Yes, same branch | No official fix |
| Our response | Patched base image, redeployed | Cloudflare WAF rules, upgrade plan |
- Containers make patching fast. A base-image bump is quick to apply, test and roll back.
- Unsupported runtimes turn hours into days. The older the version, the more code must change before a patch is even possible.
- Edge protection buys time, not safety. A WAF is a valuable first layer, never a replacement for patching.
Check your own PHP sites today
- Find the PHP version actually serving each site (not just the command-line version).
- Upgrade to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or later, then restart PHP.
- On PHP 7.x or older, plan an upgrade now and put a WAF in front in the meantime.
- If you use Cloudflare, confirm its managed ruleset is deployed with the PHP2Shell rules set to Block.
- Allow web traffic to your server only from your WAF or CDN, so attackers cannot bypass it.
- Look for signs of compromise since 20 October: new PHP files, crashes, unknown admin users.
How to fix PHP2Shell: step by step
The only complete fix is upgrading PHP to a patched release and restarting it. Here is how to do that on the most common setups.
Step 1: find the PHP version your website really uses
The command-line php -v can differ from the version serving web pages, so check both.
php -v # command-line version
php-fpm8.3 -v 2>/dev/null || ls /usr/sbin/php-fpm* # PHP-FPM version
apache2ctl -M 2>/dev/null | grep -i php # mod_php module, if used
curl -sI https://your-site.com | grep -i x-powered-by # what the site reportsNo command line? In WordPress, go to Tools, then Site Health, then Info, then Server. Or upload a file containing <?php echo PHP_VERSION;, open it in a browser, then delete it immediately.
Step 2: compare against the fixed versions
| Your PHP branch | Safe from | If older |
|---|---|---|
| 8.5 | 8.5.12 | Upgrade now |
| 8.4 | 8.4.27 | Upgrade now |
| 8.3 | 8.3.36 | Upgrade now |
| 8.2 | 8.2.35 | Upgrade now |
| 8.1, 8.0, 7.4 | No official release | Source backports only; move to 8.3+ |
| 7.3 and older, 5.x | Never | Upgrade to 8.3+ and use a WAF meanwhile |
Linux distributions often backport fixes without changing the main version number. Check the package changelog for the CVE:
apt changelog php8.3-fpm | grep -i 109618 # Debian / Ubuntu
rpm -q --changelog php-fpm | grep -i 109618 # RHEL / Alma / RockyStep 3: upgrade PHP on your platform
Ubuntu / Debian
sudo apt update
sudo apt install --only-upgrade 'php8.3*' # use your branch
sudo systemctl restart php8.3-fpm apache2 # or nginxRHEL / AlmaLinux / Rocky (including Remi packages)
sudo dnf upgrade 'php*'
sudo systemctl restart php-fpm httpd # or nginxDocker
Pin a patched base image tag in your Dockerfile, then rebuild without cache:
FROM php:8.3.36-fpmdocker compose build --pull --no-cache && docker compose up -dAvoid floating tags such as php:8 or php:latest in production; they make it hard to prove which version you run.
cPanel / WHM: update the ea-php packages through WHM's EasyApache 4, or run yum update 'ea-php*', then check each site's version in MultiPHP Manager.
Plesk: go to Tools & Settings, then Updates, and install the latest PHP components. Plesk has confirmed all PHP versions it ships are affected.
Managed or shared hosting: you usually cannot patch PHP yourself. Ask your host whether they have deployed the patched 8.x releases, and switch your site to a supported PHP version in the control panel.
Step 4: restart and verify
Running PHP workers keep the old, vulnerable code in memory until they restart. After upgrading, restart PHP-FPM or Apache, then rerun Step 1 to confirm the new version is live.
Can't patch yet? Temporary protection
These measures reduce the risk while an upgrade is prepared; none of them fully fixes PHP2Shell.
Cloudflare WAF rules for PHP2Shell
Cloudflare deployed protections on 21 October 2026 at 03:02 UTC, before public disclosure. Free-plan zones get them automatically. On Pro, Business and Enterprise plans, confirm the Cloudflare Managed Ruleset is deployed and these rules are set to Block:
| Rule | Paid ruleset ID | Free ruleset ID |
|---|---|---|
| Generic Rules - Anomalous Execution 1 | c1d409ad838f47f59446f21cc438d5dd | 4e315666e8e344cdb64119a3b5ccf32f |
| Generic Rules - Anomalous Execution 2 | f9a45927414245e3a64bb12d0a0c2f64 | 00c10e6cc4da4bd08722adeebcd95984 |
| Generic Rules - Anomalous Execution 3 | 771c654ae1154d4daa72f4e1545d163c | 48ddf592361e4fdb97a8a85982dab691 |
| Generic Rules - Anomalous Execution 4 | 217005865f0145f392300bac212afcc9 | 3556683d512a47f2937899c524b1a4c6 |
| Generic Rules - Anomalous Execution 5 | 38efdb17ea594501bb55a1d71867b12e | da07c85852e34625bb478496302ede46 |
| Generic Rules - Anomalous Execution 6 | 4148ae686fdb4d01be673fab9d9c073d | 19373a83abb840e18ab3ce5a7975ce1b |
| Generic Rules - Anomalous Execution 7 | 1389aa259617437392ce149c48143645 | 07f0b6ddaabf40b1b2042dade8d613fa |
A further rule, "Default block for High confidence Signatures" (afffe22785674c80a31875c848d2242a), sits in the new Cloudflare Managed Response Firewall Default ruleset on all plans. It inspects the server's response as well as the request.
To enable the rules on a paid plan:
- Go to Security, then WAF, then Managed rules, and deploy (or edit) the Cloudflare Managed Ruleset.
- Click Browse rules, search for "Anomalous Execution", and select all seven.
- Set Action to Block and Status to Enabled, then Deploy.
- Watch Security, then Events, filtered by these rule IDs, for blocked attempts.
Other WAFs
AWS has published guidance for applying PHP2Shell mitigations with AWS WAF. If you use another WAF or CDN, check your vendor's advisory for CVE-2026-109618 and CVE-2026-109619.
Lock your server behind the WAF
A WAF only helps if attackers cannot reach the server directly by its IP address. Allow ports 80 and 443 only from your WAF or CDN's published IP ranges (for Cloudflare, IPv4 and IPv6) in your firewall or cloud security group.
Reduce the attack surface
- Restrict file uploads. The upload-handling bug is reached through multipart requests. Block multipart form posts at the WAF on every URL except the pages that genuinely accept uploads.
- Lower request limits. Reduce
post_max_sizeandupload_max_filesizeinphp.inito the smallest values your app needs. - Turn off upload progress tracking if your app does not use it:
session.upload_progress.enabled = Off. - Hide your version:
expose_php = Offstops automated scanners from spotting vulnerable versions so easily. - Remove test scripts such as
phpinfo.phportest.phpfrom your web root.
The WAF rules are not perfect: Cloudflare reports attackers are already varying their payloads to slip past them. Treat every measure here as buying time for the upgrade.
Have you already been hit? How to check
Attacks began before the patch shipped, so a patched server may still have been compromised earlier. Check for activity since 20 October 2026.
PHP files created or changed recently in the web root:
sudo find /var/www -name "*.php" -newermt "2026-10-20" -lsPHP crashes and memory errors, a sign of exploit attempts:
sudo grep -iE "segfault|Allowed memory size" /var/log/apache2/error.log /var/log/php*-fpm.log 2>/dev/null | tail -50Unexpected scheduled jobs:
sudo crontab -l; ls -la /etc/cron.d /var/spool/cron/crontabsUnusual outbound connections:
sudo ss -tnp | grep ESTABAlso look for:
- New administrator accounts in your application or CMS.
- Unknown files in upload folders, especially
.phpfiles. - Bursts of large multipart POST requests in your access logs.
- On WordPress, new or modified plugins and unexpected UpdraftCentral connections, which attackers have abused to plant backdoors.
If you find something: isolate the server, take a snapshot for investigation, rotate every credential the app uses (database, email, API keys, SSH keys), and rebuild from a clean, patched image rather than cleaning in place. If personal or health data may have been exposed, involve your compliance team early, as notification deadlines may apply.
Takeaways
- PHP2Shell is a flaw in the PHP engine itself, so passwords, 2FA and access controls do not stop it. Only a patched PHP, restarted, does.
- Find the version that actually serves your pages, compare it with 8.5.12, 8.4.27, 8.3.36 or 8.2.35, and restart PHP after upgrading.
- Containers turned one of our cases into a same-day base-image bump; an end-of-life runtime turned the other into an upgrade project.
- If you cannot patch yet, use a WAF and lock the origin behind it, and treat both as a stopgap.
- Check for signs of compromise since 20 October, including on servers you have already patched.
- Not sure where you stand? Talk to our engineers and we will check your exposure without disrupting your service.
Need help?
If you run PHP applications and are not sure where you stand, Techdome can check your exposure without disrupting your service, protect you at the edge, and plan a safe upgrade. Contact our team to get started.

