PHP2Shell: why updating WordPress will not fix it

Updated October 21, 14:00 UTC: the fixes are out. Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35.

On October 21, 2026, the PHP security team published a security advisory for two critical vulnerabilities, both rated CVSS v4.0 9.2, that “can allow unauthenticated remote code execution”:

  • CVE-2026-109618, RCE via OOM corruption (GHSA-w8hw-w9fx-j79w). When PHP runs out of memory, it can be interrupted while its internal request data is only partly set up, and request cleanup then treats that invalid data as valid.
  • CVE-2026-109619, RCE via stale global state (GHSA-6wmf-4rv5-p3rp). Internal state that belongs to a request can survive after its memory is freed, and the next request handled by the same worker can use it before it is reset.

The advisory says all PHP installations serving web requests are at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates the risk highest for mod_php, where an unauthenticated request was shown to trigger the attack before any application code runs.

Details leaked a day early under the name PHP2Shell, and several sites took themselves offline as a precaution on the 21st, including Tweakers and the Dutch National Cyber Security Centre. Cloudflare’s CTO said that morning that Cloudflare was seeing early attacks. Germany’s BSI said no attack had been confirmed.

The fix is not a WordPress update

The wp2shell chain in July and the page-template traversal in September were bugs in WordPress core, and a WordPress release fixed them. PHP2Shell is in the interpreter that runs WordPress, and also Joomla, Drupal, Magento, Laravel, Symfony and every custom PHP script on the same server. The WordPress dashboard cannot update it, and “You have the latest version of WordPress” says nothing about it.

Where the fix comes from depends on how PHP got onto the server:

Where PHP comes from Who ships the fix What you do
Managed WordPress or shared hosting The host Ask when it is applied, then check
OS packages (Debian, Ubuntu, RHEL) The distribution’s security team Install the update, then restart PHP-FPM or Apache
Third-party repository (Ondřej Surý’s packages, Remi) The repository maintainer Install the update, then restart
Container image (php:*, wordpress:*) The image maintainer Wait for the rebuilt image, check its PHP version, redeploy every container
PHP compiled from source You Build and deploy the fixed release

Distributions received the patches in advance, according to the advisory. Remi’s repository, common on RHEL-based servers, will not have the update on October 21; PHP asks its users to switch to distribution packages or build from source.

PHP 8.1 and older get no release. For those versions the fix comes from a distribution or LTS vendor that backports it, or from a move to a supported version. Given the severity, the PHP security team also published minimal source backports for 7.4, 8.0 and 8.1 for anyone who builds PHP from source. A backport fixes this bug, not the next one, so plan the move anyway, and make it to 8.4 or 8.5: PHP 8.2 loses security support on December 31, 2026.

Why the login screen does not matter

The mod_php exploit runs before any application code. A security plugin, a hidden login URL or two-factor authentication all run after PHP has started handling the request, so none of them helps. The same goes for WordPress’s maintenance mode, because the maintenance page is itself served by PHP. Taking a site offline means stopping PHP and having the web server show a static page.

Where a static public site helps

A static public site runs that way all the time. The host that answers visitors serves files and does not run PHP, so a visitor’s request, crafted or not, has no interpreter to reach. The public site itself needs no patch, workaround or maintenance page.

Where PHP still runs

The interpreter is still part of the setup, and each of these needs the fix:

  • The WordPress origin. Editors work on it and the static build is generated from it. If the internet can reach it, it is as exposed as any other PHP server, whatever the WordPress login screen says. Access control in the web server or the network does help, because the request is refused before PHP sees it. The Preparation guide covers it.
  • Paths you forward. Forms, search or admin-ajax.php calls that a static site passes on to the live WordPress install run on the same interpreter.
  • The same server. If the static output is deployed to a local directory on the machine that also runs WordPress, the site visitors see is static, but PHP still runs there.
  • Other PHP applications. A static marketing site does not cover the shop, the customer portal or the old Joomla site on the same network.

On Staatic Cloud, WordPress origins sit behind HTTP authentication that the proxy checks before a request reaches PHP. The exceptions are a few endpoints the platform itself uses and any origin rules you configured, and those requests do reach PHP. The PHP runtime is part of the WordPress image we build, so the fix reached every site through a platform update on October 21, not through the dashboard; see PHP2Shell on Staatic Cloud.

What to do now

  1. List every PHP runtime. Production, staging, old campaign sites, internal tools and anything that bundles PHP. For WordPress, Tools → Site Health → Info → Server shows the PHP version the web server uses, which can differ from php -v on the command line.
  2. Update from the same source. Ubuntu and Red Hat often backport fixes without changing the PHP version number, so look the CVE IDs up in your distribution’s security tracker and check the package version, not php -v. Debian ships the new upstream release. For containers, check the image that is actually running.
  3. Restart everything that runs PHP. PHP-FPM, Apache with mod_php, queue workers and other long-running PHP processes keep the old code until they restart, and a container keeps its old image until it is redeployed.
  4. If you cannot update yet, reduce exposure. The advisory lists measures that “reduce exposure to specific attack paths but do not make an installation safe”:
    • Set session.upload_progress.enabled=0 and restart every worker. Set it in php.ini, the FPM pool or the server configuration, not with ini_set() or an FPM .user.ini.
    • Set memory_limit=-1 in a way applications cannot override, such as php_admin_value in the FPM pool or Apache configuration, and keep a container or cgroup memory limit as the availability boundary.
    • Lower post_max_size: 8M for sites without uploads, 32M with them.
    • On PHP 8.5, also set fatal_error_backtraces=0 and restart every worker.
    • Taking a site offline is safer than any of these. Stop PHP rather than only removing the PHP handler, or the web server may serve your .php files as plain text.
  5. Decide about old PHP. A site on PHP 8.1 or older needs a backported build now and a move to 8.4 or 8.5 soon.

Start with the PHP the internet can reach. On a static WordPress setup that is usually only the forwarded paths and any origin not yet behind access control.

To check your own site from the outside, run our exposure check. It shows the PHP version your server reveals, flags releases without the fix, and lists which WordPress addresses answer anyone. Distributions and hosts often patch PHP without changing its version number, and many servers hide it, so confirm with your host or in your distribution’s security tracker.

If you would rather keep PHP off your public site, Staatic Cloud publishes your WordPress site as static files and keeps the origin behind a login, and we patched every Cloud site on the day of the release. You can try it free for 14 days.