On October 21, 2026, the PHP project released emergency security updates for two critical vulnerabilities in the PHP engine itself, CVE-2026-109618 and CVE-2026-109619, both rated CVSS v4.0 9.2. Together they're being called PHP2Shell. They can let an unauthenticated attacker run code on a web server, or read sensitive data out of PHP's memory, without any flaw in the application running on top.

If you run anything built on PHP, including WordPress, Drupal, Joomla, Magento, WooCommerce, Laravel or a custom app, treat this as an emergency. Here's what we know, what to patch, what to do if you can't patch today, and what to check afterward.

What happened

The vulnerabilities were found independently by Wiz Research and by Calif working with OpenAI, and disclosed in coordination with the PHP security team. PHP published fixed releases and a security advisory at 14:00 UTC on October 21.

A few facts make this one unusually serious:

  • It's in PHP, not in your application. Wiz demonstrated pre-authentication remote code execution against default WordPress, Drupal and Joomla installs, and notes that even a trivial "Hello World" app on an affected PHP version can be vulnerable. Clean application code doesn't protect you.
  • It goes back a long way. According to the researchers, the affected code paths date back to PHP 5.4, released in 2012.
  • It also leaks memory. Separately from code execution, one of the issues can return chunks of a PHP worker's memory to the attacker. That memory can contain passwords, session tokens, API keys and other secrets from other users' requests.
  • Exploitation is underway. Sansec reports that Cloudflare saw early attacks against PHP sites on the morning of October 21, before the release, and the technical write-ups are now public. Assume mass exploitation.

How it works, briefly

Both CVEs come from the same root problem: how PHP cleans up when a request hits a fatal error partway through, especially an out-of-memory error. In PHP's words, out-of-memory handling can interrupt PHP while internal request data is only partially initialized (CVE-2026-109618), and request-owned internal state can survive after its memory has been freed (CVE-2026-109619).

In practice, an attacker sends a request designed to make PHP run out of memory at the wrong moment, typically a crafted multipart/form-data upload that PHP parses before your application code even runs. The worker is left holding pointers to freed memory. The attacker's next request, handled by the same worker, reuses that stale state. Depending on the code path, that becomes a memory leak (Wiz showed worker memory coming back inside a PHPSESSID cookie, even on apps that never use sessions) or controlled memory corruption leading to code execution.

PHP says every installation serving web requests is at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. It rates the risk highest for mod_php.

The researchers also say frontier AI models were critical to turning these long-standing bugs into working exploits quickly. Whatever you make of that, the practical takeaway for defenders is the same: the gap between disclosure and reliable exploitation is shrinking, and "too complex to exploit" is no longer a safe assumption.

Step 1: Patch now

The only complete fix is updating PHP. The fixed releases are:

BranchFixed versionNotes
PHP 8.58.5.12
PHP 8.48.4.27
PHP 8.38.3.36
PHP 8.28.2.358.2 reaches end of life on December 31, 2026. Plan your upgrade.
PHP 8.1 and olderNo official releasePHP published minimal source backports for 7.4, 8.0 and 8.1. Otherwise, use a distribution or LTS vendor backport, or upgrade.

A few practical points:

  • Use your vendor's packages. PHP says Linux distributions and LTS vendors received the patches in advance, so check for updated packages first.
  • Remi's repository was not updated on day one. If your RHEL-family servers install PHP from rpms.remirepo.net, PHP recommends switching to distribution packages or building from source so you can patch immediately.
  • Managed hosting and PaaS: you can't fix this in your application code. Ask your provider when PHP will be updated, and get the answer in writing.
  • Restart every worker. Updating packages without reloading PHP-FPM or restarting Apache leaves the old code running.
  • Find all of it. PHP hides in containers, old base images, vendor appliances, internal tools and that one marketing site nobody owns. Rebuild container images rather than patching running containers. If you don't have a reliable inventory, this is when that costs you. See our asset inventory guide.

Step 2: If you can't patch today

PHP is clear that no mitigation makes an installation safe, but these reduce exposure while you schedule the update. From PHP's advisory:

For CVE-2026-109618 (out-of-memory corruption)

  • Set memory_limit=-1 in a way applications can't override, such as php_admin_value in the FPM pool or Apache configuration. Watch server memory closely, because one request can now use all of it, and use a container or cgroup limit as the availability boundary. PHP specifically warns not to use RLIMIT_AS or RLIMIT_DATA instead.
  • Lower post_max_size: 8M if you don't need uploads, 32M if you do, with upload_max_filesize below it.
  • Enforce request size, field count, multipart part count and header limits at the web server or proxy.

For CVE-2026-109619 (stale global state)

  • Set session.upload_progress.enabled=0 in php.ini, the FPM pool or server configuration, and restart every worker. ini_set() and .user.ini don't work for this.
  • On PHP 8.5, set fatal_error_backtraces=0 and restart every worker.
  • Remove invalid or deprecated per-request settings that emit diagnostics early, and fix fatal errors and timeouts an attacker can trigger. Suppressing errors with @ or display_errors doesn't help.

At the edge

  • WAF rules. Cloudflare and other providers have deployed rules for the known exploits. They're a stopgap, and they only help if your origin refuses traffic that doesn't come through the WAF.
  • Block multipart requests. Sansec notes that all known triggers arrive as multipart/form-data. Blocking those at the web server stops the known paths but breaks every file upload, and on some sites checkout forms too. Test before relying on it.
  • Take it offline. For a site that can't be patched and doesn't need to be up, a static maintenance page served without PHP is the safest option. Application maintenance modes don't help, because PHP parses the request before the application checks the flag.

Our post on compensating controls when you can't patch covers how to document temporary measures like these.

Step 3: Check whether you were hit

These attacks happen below the application, so application logs may show very little. Wiz suggests looking for:

  • Unusual multipart requests followed by memory-limit errors or repeated HTTP 500 responses.
  • Unexpectedly large or malformed PHPSESSID cookies in responses.
  • Unexplained PHP worker crashes, restarts or churn.

Then check for what usually follows a successful RCE: web shells and unexpected PHP files, modified core or plugin files, new admin accounts, new scheduled tasks and unexpected outbound connections from web servers.

Rotate secrets on exposed systems. Because the memory disclosure can leak data from other requests without leaving much trace, assume anything that passed through an internet-facing PHP worker since exploitation began could have been exposed. That includes database passwords, API keys, session signing keys and admin sessions. Prioritize payment, identity and cloud credentials.

What this means for PCI DSS and your other obligations

PCI DSS Requirement 6.3.3 requires critical security patches to be installed within one month of release, and a pre-auth RCE with public exploits on payment-facing systems should be patched well inside that. If PHP runs anywhere in or connected to your cardholder data environment, document when you patched, any interim mitigations, and the results of your compromise checks. Your assessor will ask, and so will your cyber insurer.

If a system can't be patched because it's on PHP 8.1 or older, you're now also dealing with end-of-life software risk. This is a good time to get the upgrade funded.

For the general process of handling events like this, see our emergency patching playbook for zero-days.

How we can help

If you need help finding every PHP instance in your environment, confirming patches actually took effect, or checking exposed systems for compromise, email [email protected]. Our vulnerability management and web application penetration testing teams can verify your PHP applications after you patch. As with every engagement, there's nothing to pay up front, you pay only once the work is complete, and the work is covered by our 100% money-back guarantee.

Key takeaways

  • PHP2Shell (CVE-2026-109618, CVE-2026-109619) is a pair of critical flaws in the PHP engine that allow unauthenticated remote code execution and memory disclosure, independent of your application.
  • Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 now, restart every worker, and rebuild container images. Versions 8.1 and older need a vendor backport or an upgrade.
  • If you can't patch today, apply PHP's interim mitigations and WAF protection, or take the site offline. None of them is a fix.
  • Look for signs of exploitation, and rotate secrets on internet-facing PHP systems.
  • Document everything for PCI DSS 6.3.3 and your insurer.
About the author. Marcello Duarte is a cybersecurity consultant at Radical Security and the author of this blog. He leads penetration testing and vulnerability management engagements, and previously worked in vulnerability research, where he discovered CVE-2015-7392. To work with Marcello, email [email protected].