PHP2Shell is a pair of critical bugs in PHP itself, tracked as CVE-2026-109618 and CVE-2026-109619. They can let an attacker who is not logged in run code on any server that serves PHP pages. The fix is a PHP update: 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or your distribution's patched package, followed by a restart of every PHP worker.
Details leaked on 20 October, two days before the planned disclosure, and the PHP project shipped the fixes a day early on 21 October. If you run anything on PHP (WordPress, WooCommerce, Drupal, Magento, Laravel, a control panel), check your version today.
What is PHP2Shell?
PHP2Shell is the name researchers gave to two remote code execution bugs in the PHP runtime. Researchers at Calif, Wiz, OpenAI and Quarkslab reported them. PHP rates both 9.2 on CVSS v4.0.
| CVE | PHP's name | What goes wrong |
|---|---|---|
| CVE-2026-109618 | RCE via OOM corruption | PHP runs out of memory partway through setting up a request. Cleanup code then trusts data that was only half built. |
| CVE-2026-109619 | RCE via stale global state | Internal state from one request outlives the memory it points to. The next request on the same PHP worker can act on that leftover data. |
The bugs sit in how PHP parses an incoming request, before your application code starts. Updating WordPress, a plugin or your framework does nothing here. The PHP binary has to change.
PHP's advisory names every setup that serves web requests: PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates Apache with mod_php as the highest risk, with a demonstrated exploit where one unauthenticated request triggers the attack before any application code runs. The advisory also describes RCE through the session upload progress feature on PHP-FPM, under suitable application conditions.
Which PHP versions are affected?
Everything before the four fixed releases. This is what PHP's advisory and its security releases from 21 October say:
| PHP branch | Fixed version | Notes |
|---|---|---|
| 8.5 | 8.5.12 | Active support |
| 8.4 | 8.4.27 | Active support |
| 8.3 | 8.3.36 | Security fixes only |
| 8.2 | 8.2.35 | Security fixes end 31 December 2026 |
| 8.1, 8.0, 7.4 | No PHP release | PHP published minimal source backports; distributions and LTS vendors ship their own |
| 7.3 and older | No fix from PHP | Upgrade, or use a vendor that still patches it |
Cloudflare and Imperva say the bugs reach back to PHP 5.4. The PHP advisory lists all versions below the fixed releases as affected and does not name a first affected version.
Your version number may look old and still be patched. Linux distributions backport fixes and keep the old upstream number. Ubuntu 24.04 ships the fix as 8.3.6-0ubuntu0.24.04.13, which still reports 8.3.6. Debian 12 has 8.2.35-1~deb12u1 (DLA-4848-1) and Debian 13 has 8.4.27-1~deb13u1 (DSA-6574-1). Compare the full package version against your distribution's security tracker, not just the first three numbers.
Is PHP2Shell being exploited?
Reports conflict, and they change by the hour. What the sources said, in order:
- 17 October: Amazon Threat Intelligence logged a PHP2Shell exploit attempt on its MadPot honeypots, four days before the patches. The request came from an IP address tied to a commercial anonymization service.
- 20 October: details leaked online. watchTowr confirmed the bugs were real. Huntress said it had seen no exploitation and knew of no public exploit code.
- 21 October, 03:02 UTC: Cloudflare switched on WAF rules for PHP2Shell. It later wrote that it saw attack traffic against its customers, with attackers changing the payload to get around the rules.
- 21 October, 14:00 UTC: PHP released the fixes. watchTowr reported exploitation of both bugs on its honeypot network the same day.
- 21 October, afternoon (US): the PHP Foundation's executive director told CNBC there was no evidence of working exploits, only "incomplete, misguided, and non-working generated ones." Imperva reported no matching traffic during its own pre-disclosure monitoring.
- 23 October: neither CVE is in CISA's Known Exploited Vulnerabilities catalog yet (its last update was 21 October).
The researchers built working exploits, and other teams say they reproduced the bugs. Assume attackers can too. Treat every unpatched, internet-facing PHP server as exposed.
How to check your PHP version
Check the PHP that serves web requests. On many servers the command line PHP is a different build from the one behind the website.
On the server:
php -v # command line PHP
php-fpm8.3 -v # the FPM build (the name varies: php-fpm, php-fpm8.4)
apachectl -M | grep php # a php_module line means Apache runs PHP as mod_php
dpkg -l | grep php # Debian/Ubuntu: the full package versions
rpm -qa | grep php # RHEL, Rocky, Alma, Fedora
From the browser: put a file called info.php containing <?php phpinfo(); in your web root, open it, read the version at the top and the Server API line (it tells you FPM, Apache 2.0 Handler or CGI). Delete the file right after, since it shows your whole configuration.
In WordPress: go to Tools > Site Health > Info and open Server. The PHP version line is the one your site runs on.
In a hosting panel: cPanel shows it under MultiPHP Manager or Select PHP Version, Plesk under the domain's PHP settings, and most managed hosts on the site's overview page.
In Docker: docker exec <container> php -v reports the PHP inside the running container, which is the one that matters.
To test from the outside, Searchlight Cyber has published an open-source checker, php2shell-scanner, according to Help Net Security. Run it only against hosts you own.
How to patch PHP2Shell
The order that holds for every stack: internet-facing servers first, then restart every PHP process. A patched binary on disk does nothing while old workers keep serving requests.
Debian and Ubuntu
sudo apt update && sudo apt upgrade
sudo systemctl restart php8.3-fpm # match your version
sudo systemctl restart apache2 # if you use mod_php
Then check the package versions with dpkg -l | grep php against the Debian or Ubuntu security tracker. On Ubuntu 20.04 and older, the fixed 7.x packages come through Ubuntu Pro. Third-party repositories update on their own schedule: Help Net Security reported that rpms.remirepo.net had no update on release day, so confirm yours has shipped before you rely on it.
RHEL, Rocky, AlmaLinux and Fedora
Run sudo dnf upgrade 'php*', then restart php-fpm and httpd. Check your vendor's advisory for the fixed package version, since it will not match the upstream number.
Docker images
The official php images on Docker Hub got 8.5.12, 8.4.27, 8.3.36 and 8.2.35 tags on 21 October. Pin one, rebuild and redeploy:
FROM php:8.4.27-fpm
docker compose build --pull && docker compose up -d
A running container keeps its old PHP until you replace it. Images built on top of php (including wordpress) need a fresh pull and redeploy too.
Shared hosting and cPanel
You cannot patch PHP yourself here. The host updates the PHP builds the panel offers (EasyApache's ea-php or CloudLinux's alt-php on most cPanel servers). Check the host's status page or ask support whether their PHP builds include the fixes for CVE-2026-109618 and CVE-2026-109619. If your site still runs 7.4 or 8.1, switch it to 8.3 or newer in MultiPHP Manager or Select PHP Version, after testing on a staging copy if you have one.
Managed WordPress hosting
Your host patches PHP for you. WordPress.org says no WordPress update is required or planned for these bugs. Confirm the host has rolled out the fix, then check Site Health > Info > Server. If the site is on PHP 8.1 or older, move it up, since those branches only get vendor backports.
Windows and builds from source
Fixed sources and Windows binaries are on the php.net downloads page. For 7.4, 8.0 and 8.1, PHP published minimal source backports for people who build PHP themselves.
If you cannot patch today
PHP is blunt about this: only an update is a complete fix. Its advisory lists settings that block specific attack paths without making a server safe:
- Set
session.upload_progress.enabled=0inphp.ini, the FPM pool or the server config (notini_set()or.user.ini), then restart every worker. This blocks the confirmed session paths. - On PHP 8.5, set
fatal_error_backtraces=0and restart every worker. - Set
memory_limit=-1in a way applications cannot override, such asphp_admin_value. Pair it with a lowpost_max_size(8M without uploads, 32M with) and a container or cgroup memory limit. Do not useRLIMIT_ASorRLIMIT_DATA, which can trigger the bug. - Cap request size, field count, multipart parts and nesting depth at the web server or proxy, and block multipart requests if the site never takes uploads.
Test each change before you roll it out, since some break uploads. If a server cannot be patched or mitigated in time, the UK NCSC and WordPress.org both say to consider taking it offline, or put it behind a VPN or an allowlist so only known addresses reach it.
Cut exposure while you patch
None of the above stops a scanner from sending requests. Mass exploitation of a fresh bug is automated: scripts sweep the internet for PHP servers and fire the exploit at each one. Those scanners usually run on rented servers in hosting and datacenter networks, or route through VPNs, proxies and Tor. Amazon's first sighting came from an anonymization service. Real visitors rarely browse from a datacenter.
That gives you a second layer for the days it takes to patch everything: refuse requests from those networks before they reach PHP. IPScanner does not detect PHP2Shell and does not fix PHP. It checks who is connecting, sorts each visitor into a class (human, verified crawler, malicious automation, hosting, Tor, VPN, proxy and a few more), and blocks the classes you choose.
The check has to run in front of PHP. PHP2Shell fires while PHP parses the request, so anything that runs inside PHP starts too late.
| Your setup | Where the check runs | Guide |
|---|---|---|
| Site behind Cloudflare | Cloudflare Worker, before Cloudflare forwards to your origin | Cloudflare Worker |
| Traefik in front of PHP | Traefik plugin, before the request reaches the container | Traefik plugin |
| Caddy in front of PHP-FPM | Caddy module, before php_fastcgi | Caddy module |
| nginx in front of PHP-FPM | Forward-auth gate via auth_request, before fastcgi_pass | nginx gate |
| WordPress or WooCommerce only | The plugin runs inside PHP, so it cannot stop this attack | WordPress plugin |
The WordPress plugin and the WooCommerce checks stop fake signups, spam and card testing at your forms. They are the wrong layer for PHP2Shell. A WordPress site on a single Apache server with nothing in front gets the fastest gate by putting Cloudflare and the Worker in front of it.
Look up an IP from your access logs
Run monitor mode first, then block. Monitor mode records every verdict and blocks nothing, so you see who is hitting your PHP endpoints before you change anything. After a few hours, set hosting, Tor and malicious automation to block. VPN and proxy are a judgment call: block them on an admin panel, think twice on a public store. Verified search engines and AI crawlers from the crawler directory always pass.
Blocking needs the Starter plan. On the Free plan a site runs in monitor mode only. New accounts get seven days of Starter features with no card, which covers a patch window. See pricing.
Be clear about the limits:
- An attacker on a home connection or a residential proxy that the checks miss still reaches PHP.
- The gates fail open. If the IPScanner API is slow or unreachable, requests pass, so the site stays up.
- A gate only helps if traffic goes through it. If your origin answers on its public IP, a scanner skips Cloudflare entirely, so let the origin accept connections from Cloudflare's IP ranges only.
If your site is on Cloudflare, also leave its managed WAF rules on. Cloudflare says its PHP2Shell rules have run by default on every plan since 21 October. Those rules look at the request itself; IPScanner looks at who sent it. Neither replaces the patch.
Check whether someone got in
If a server sat unpatched and exposed since mid-October, look before you move on. The advisories and incident responders point at the same signs:
- large or deeply nested multipart POST requests to
.phppaths, often withPHP_SESSION_UPLOAD_PROGRESSin the body - "Allowed memory size exhausted" errors and bursts of crashed or respawned PHP workers in the error logs
- new or changed files in the web root, new cron jobs or user accounts
- PHP or web server processes starting shells or making outbound connections you do not recognise
If you suspect a compromise, isolate the server and preserve logs before you restart anything, then rotate every secret PHP could read: database passwords, API keys, session keys.
PHP2Shell checklist
- List every PHP install you run, internet-facing first, including control panels, appliances and containers.
- Find the version that serves web requests (phpinfo, Site Health,
php-fpm -v), not justphp -v. - Install 8.5.12, 8.4.27, 8.3.36, 8.2.35 or your distribution's fixed package.
- Restart every PHP-FPM pool, Apache and LiteSpeed worker; rebuild and redeploy containers.
- On 8.1 or older, get a vendor backport or upgrade; if neither is possible, take the site offline or allowlist it.
- Can't patch yet? Apply PHP's interim settings and restrict access.
- Put a gate in front of PHP (Cloudflare, Traefik, Caddy, nginx), monitor first, then block hosting, Tor and malicious automation.
- Lock your origin to the proxy in front of it.
- Search your logs from 17 October onward for the signs above.
- Rotate secrets on any server that was exposed and unpatched.
Sources: PHP security advisory, GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp, WordPress.org, Cloudflare, watchTowr FAQ, watchTowr, Help Net Security, SecurityWeek, The Hacker News, CNBC, Imperva, Qualys, Armis, Ubuntu, Debian.
FAQ