PHP2Shell is fixed by updating PHP and then restarting it. If you cannot do that today, the stopgaps below buy time. None of them is a fix.
Last updated 22 October 2026. We will update this article as the facts change.
PHP2Shell is two critical flaws in PHP itself, fixed on 21 October 2026. We have patched every server we manage. This is the practical version: what to do, how to prove it worked, and what happened when we tried the advice everyone was sharing.
In short
- What happened: PHP, the software WordPress and many other websites run on, had two serious security holes announced on 21 October 2026. Together they are known as PHP2Shell.
- Why it matters: an attacker could take over a website without needing a password.
- Updating WordPress or your plugins does not fix it. The fix has to be installed on the server itself.
- What to do: ask your host or developer two questions. Has PHP been updated on my server? And has it been restarted since? Both answers need to be yes.
- On an older PHP version (7.4, 8.0 or 8.1)? Ask about that specifically. A fix exists, but it comes from your host, not from the PHP project.
- If we manage your site, this is already done, and we will email you about your own sites.
The rest of this article is for developers and server administrators.
What is PHP2Shell?
PHP2Shell is two flaws in the PHP engine, CVE-2026-109618 and CVE-2026-109619, that let an attacker run code on a server without logging in. Both are rated 9.2 on CVSS v4.0, and PHP fixed them in 8.2.35, 8.3.36, 8.4.27 and 8.5.12.
The flaws sit below the application, so a clean WordPress, Magento or Drupal install is as exposed as a neglected one. Sansec reports that the vulnerable code dates back to PHP 5.4.0 in 2012. Researchers at Calif showed working attacks against WordPress, Magento, Drupal, Joomla, Nextcloud and others.
PHP’s advisory for CVE-2026-109618 confirms full remote code execution on Apache with mod_php in default settings. PHP-FPM is susceptible by source analysis. Sansec adds that CVE-2026-109618 can leak fragments of server memory in a session cookie, which may include other visitors’ data.
Is my site affected by PHP2Shell?
Yes, if it runs a PHP version older than the fixed releases, whatever application sits on top. WordPress core and plugin updates change nothing here, and neither does maintenance mode, because PHP reads the request before WordPress ever sees it.
To find your version, look in your hosting panel, or in WordPress under Tools, Site Health, Info, Server. On the command line php -v works, but the command-line PHP is not always the one serving your site. For PHP 7.4, 8.0 and 8.1 the version number proves nothing either way; see the backport section below.
How do I fix PHP2Shell?
Install a fixed PHP build, restart every PHP process, then verify. PHP’s own wording is that “there are no complete mitigations, updating is the only safe choice.”
- Get a fixed build from wherever your server’s PHP comes from.
- Restart PHP, not just reload it.
- Prove the old code is gone, using the checks below.
The fix reaches your server when your PHP source rebuilds it, not when php.net publishes. A server gets PHP from its Linux distribution, a third-party repository, a control panel or a container image. On the day, we watched fixed builds appear from different sources at different times. Not every PHP branch arrived at once. On managed hosting, ask your host where your PHP comes from and whether that source has shipped the fix.
What if I am on PHP 8.1 or older?
php.net released no new 7.4, 8.0 or 8.1 build; it published a small source patch, and packagers turned it into builds on 21 October. The fixed packages keep the old version number, so 7.4.33 is still 7.4.33.
Backports were published by, among others, Ondřej Surý’s Debian and Ubuntu repositories, Plesk, cPanel, DirectAdmin, CloudLinux and Red Hat; Digital Applied keeps a tracker. For sites that cannot leave PHP 7.4 yet, we used a control panel’s own rebuild and the Sury Debian packages.
A backport closes this flaw; it does not make PHP 7.4 supported again. Upgrading stays on the list, just without today’s deadline.
How to tell a backport is installed
Check the package, not the version number. On Debian or Ubuntu the package revision carries the build date, and the changelog names the CVEs:
dpkg -l 'php7.4*' | grep ^ii
zgrep -E 'CVE-2026-10961[89]' /usr/share/doc/php7.4-fpm/changelog.Debian.gz
A fixed Sury build reads like 7.4.33-31+0~20261021...; the date in the revision is the tell. On a panel, check the build date it shows. Watch for two traps. A panel’s own interface runs on PHP too and can need a separate update, as Plesk’s advisory notes. And on some backports the session upload progress setting still reads “on”, although the fix disables the feature in code.
An updated package is not a patched server
The PHP2Shell code keeps running until every PHP process has restarted. Installing the package changes the files on disk, not the processes already in memory.
With PHP-FPM, the distribution package normally restarts the service on install. We checked rather than assumed, by comparing the service start time with the install time.
With Apache and mod_php, a graceful reload was not enough in our testing. The Apache workers still had the old, deleted PHP library loaded. Only a full restart replaced it. That matters because mod_php is exactly the setup PHP’s advisory confirms as exploitable.
Two read-only checks, run as root:
# any process still using a deleted (old) PHP library? No output is good.
grep -l 'libphp.*(deleted)' /proc/*/maps 2>/dev/null
# PHP-FPM: did the service start after the update was installed?
systemctl show php8.3-fpm -p ActiveEnterTimestamp
What can I do if I cannot patch PHP2Shell yet?
Add layers that buy time, starting with the strongest, and know what each one costs you.
Take PHP offline, or make the site read-only
Stopping PHP and serving a static page is the strongest stopgap. Sansec reports that a PHP core developer called it the most sensible option before the release. A middle way is to let the web server answer only GET and HEAD requests. Visitors can browse, but logins, checkout, forms and plugin background requests stop. We did not test the read-only option on our sites.
Block upload requests, and test what it breaks
The most repeated advice was to reject every multipart/form-data request before it reaches PHP. Sansec itself warns this breaks uploads and some checkouts. We tested it on our own site first, and it refused 24 legitimate requests in a short test window, including a plugin’s page-view counter and an admin background request. Plugins send ordinary background requests as multipart, not just file uploads.
An exception by URL cannot work, because PHP reads the body before WordPress knows anything. An exception by trusted IP address can. We removed the block: on a site where customers or staff upload anything, it stops the business. It suits a site that takes no uploads, and even then it needs testing. A block that hurts real visitors is not a fix.
Change PHP settings, where they will survive
session.upload_progress.enabled = 0 closes one confirmed path, not all of them. PHP’s advisory for CVE-2026-109619 says it “blocks the confirmed session paths but not other variants”, and watchTowr goes further: ini-file mitigations “should be understood to be ineffective.”
We applied it anyway to every PHP version still waiting for a fix, as one layer, and removed it once that version was patched. It cannot be set from application code; ini_set() has no effect. We used a separate drop-in file, which survives control panels that regenerate pool files. On Debian or Ubuntu with PHP-FPM, for PHP 8.1:
# apply: one file, test the config, reload
echo 'session.upload_progress.enabled = 0' | sudo tee /etc/php/8.1/fpm/conf.d/99-php2shell-interim.ini
sudo php-fpm8.1 -t && sudo systemctl reload php8.1-fpm
# verify what PHP-FPM uses: expect "Off"
php-fpm8.1 -i | grep session.upload_progress.enabled
# undo: delete the file, test, reload
sudo rm /etc/php/8.1/fpm/conf.d/99-php2shell-interim.ini
sudo php-fpm8.1 -t && sudo systemctl reload php8.1-fpm
If the test or the check fails, undo it straight away. A pool setting can still override the file, so also check a request served by the site, not php -i on the command line.
The published list also includes memory_limit = -1. We did not adopt it. PHP’s own advisories do not recommend it, and with no memory cap a single request can exhaust the whole server.
Your CDN’s emergency rule is a layer, not a fix
Cloudflare deployed emergency rules automatically, including on free plans. It also reported attackers “mutating the attack payload to try to bypass our protections.” Requests sent straight to your server’s IP address never pass the CDN at all. And a single skip rule can switch off managed protection without anyone noticing.
What the PHP2Shell attack traffic looked like
PHP2Shell attacks started before the fix existed, and reports on the scale differ. On 21 October, SecurityWeek reported that watchTowr saw attempts with no successes. Hadrian described exploitation “at scale”. Sansec reports Cloudflare saw early attacks at 07:43 UTC.
The first attempt we saw:
| Source | 64.95.12.7, BL Networks, US |
| Time | 09:16:54 UTC, 21 October 2026, about five hours before PHP’s fixed release |
| Request | one POST / |
| User agent | php2shell-109618 |
| Outcome | no evidence of compromise |
Public proof-of-concept tools also use user agents such as JACKALPOC and B7kQpoc61x. That is a weak signal: any attacker can change it.
Was my server compromised?
No official indicators of compromise had been published when we checked, so we looked for behaviour instead. These are the signals we checked:
- PHP starting a downloader, network tool, script interpreter or shell
- PHP running
whoamiorid - a PHP process connected outwards to an unusual port
- PHP files appearing in upload or temporary folders
- new PHP files in
wp-adminorwp-includeswith no WordPress update - a changed crontab or SSH
authorized_keysfor the site’s user - PHP crashes and memory-exhaustion errors, because both flaws are triggered by making PHP fail
Two lessons from running them. Some form plugins write tiny placeholder PHP files into uploads that look like web shells at first glance. And a point-in-time check misses short-lived processes; process auditing is stronger. A clean log does not prove a clean server; that is PHP’s own wording.
If a site was unpatched and exposed to PHP2Shell, the memory leak is a reason to consider rotating the passwords and keys it held.
What we got wrong on the day
- We first believed both flaws needed an upload request. Much early coverage said so. PHP’s advisory says fatal errors and out-of-memory conditions trigger them too. The upload block went from main mitigation to partial at best.
- We dropped a PHP setting we had planned, because no source explained why it would help. An unexplained change during an incident is a new problem.
- One automated run reported success while installing nothing. It was caught only because every step checks the result instead of trusting the exit status.
PHP2Shell timeline
| Date (UTC) | Event |
|---|---|
| August 2026 | Calif, OpenAI and Wiz Research report the flaws to PHP |
| 20 October | Details leak; PHP announces a release for the next day |
| 21 October, 03:02 | Cloudflare deploys emergency WAF rules |
| 21 October, 07:43 | Cloudflare reports early attacks |
| 21 October, 09:16 | The first attempt we saw |
| 21 October, 14:00 | PHP releases 8.2.35, 8.3.36, 8.4.27 and 8.5.12 |
| 21 October | Packagers ship backports for 7.4, 8.0 and 8.1 |
Sources
The flaws were found by Ryan Austin of Calif, by Wiz Research (Sagi Tzadik, Shir Tamari, Nir Ohfeld and Tomer Schwartz) and by OpenAI; the PHP security team coordinated the fix.
- PHP, news archive 2026, https://www.php.net/archive/2026.php, retrieved 2026-10-21
- PHP, GHSA-w8hw-w9fx-j79w (CVE-2026-109618), https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w, retrieved 2026-10-21
- PHP, GHSA-6wmf-4rv5-p3rp (CVE-2026-109619), https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp, retrieved 2026-10-21
- Sansec, PHP2Shell: Critical PHP RCE, https://sansec.io/research/php2shell, retrieved 2026-10-21
- Cloudflare, emergency WAF protection, https://blog.cloudflare.com/php-vulnerabilities-waf-protection, retrieved 2026-10-21
- watchTowr, PHP2Shell, https://watchtowr.com/intelligence/php-remote-code-execution-php2shell/, retrieved 2026-10-21
- Ondřej Surý, Debian 12 package index, https://packages.sury.org/php/dists/bookworm/main/binary-amd64/Packages.gz, retrieved 2026-10-22
- Plesk, CVE-2026-109618 and CVE-2026-109619 in PHP shipped with Plesk, https://support.plesk.com/hc/en-us/articles/44397729587351, retrieved 2026-10-22
- Digital Applied, PHP2Shell fixes by distro and control panel, https://www.digitalapplied.com/blog/php2shell-fixes-by-distro-control-panel-php-version, retrieved 2026-10-22
- ComputingForGeeks, PHP2Shell: check if your PHP is vulnerable, https://computingforgeeks.com/php2shell-cve-2026-109618-check-patch/, retrieved 2026-10-22
- SecurityWeek, PHP2Shell patches land as first exploitation attempts hit sensors, https://www.securityweek.com/php2shell-patches-land-as-first-exploitation-attempts-hit-sensors/, retrieved 2026-10-22