← All insights
Security Advisory 9 min read

PHP2Shell: Two Critical PHP Flaws, What to Do Now

PHP2Shell lets an unauthenticated attacker run code on servers that serve PHP. Fixed versions, where PHP hides in your business, and what to do first.

Advisory at a glance

critical CVSS v4.0 9.2 Actively exploited
Affected
PHP 8.2, 8.3, 8.4, and 8.5 before the October 21 releases, plus end-of-life 8.1 and older.
Fixed in
PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35.
What to do
Update PHP everywhere it serves web requests, starting with Apache mod_php hosts.
On this page
  1. The short version
  2. What actually went wrong
  3. Why this one is louder than usual
  4. Who is exposed
  5. Fixed versions
  6. How to find out what you’re running
  7. What to do, in order
  8. What this looks like from a monitored environment
  9. Sources

Field notes from the engineering team

On October 21, 2026, the PHP project shipped emergency releases for two critical vulnerabilities that together have picked up the name PHP2Shell. Both let an unauthenticated attacker run code on a vulnerable web server. Both are rated 9.2 on CVSS v4.0. And on the most common Apache setup, the attack works before a single line of your application’s code has run.

PHP runs a large majority of the web, including every WordPress, Drupal, Joomla, and Magento site, and the control panels (cPanel, Plesk) that a lot of small businesses manage their hosting through. If your organization has a website, a customer portal, an intranet, or an appliance with a web interface, there is a good chance PHP is in the picture somewhere, and this is the week to find out exactly where.

This post walks through what the bugs are, who is exposed, which versions fix them, and what to do if you can’t patch today.

The short version

ItemDetail
CVEsCVE-2026-109618 (“RCE via OOM corruption”) and CVE-2026-109619 (“RCE via stale global state”)
SeverityCritical, CVSS v4.0 9.2 for both
ImpactUnauthenticated remote code execution as the web server’s worker account
AffectedPHP 8.2, 8.3, 8.4, and 8.5 before the October 21 releases; end-of-life branches (8.1 and older) are affected and get no update from the PHP project
Fixed inPHP 8.5.12, 8.4.27, 8.3.36, 8.2.35
Highest riskApache with mod_php, where the bug is reachable on default settings before any application code runs
ExploitationDetails leaked a day early; scanning and exploitation attempts were observed within hours of the patch

What actually went wrong

Both bugs live in how PHP cleans up after a request when something interrupts it at the wrong moment. Neither one is a flaw in a specific function you can grep your code for. They are in the engine itself, which is why the fix is a new PHP build and not a code change.

CVE-2026-109618 is about running out of memory. Every PHP request has a memory_limit. If an allocation fails while PHP is still setting up the request’s internal structures, PHP’s out-of-memory handling bails out early and leaves those structures half-initialized. The request shutdown code then treats that half-built state as valid, and an attacker who controls the size and shape of the request can turn that into memory corruption and, from there, code execution. On Apache with mod_php, PHP’s own advisory confirms this is reachable over plain HTTP with default input and memory limits, and PHP-FPM has been confirmed exploitable through application-level paths as well.

CVE-2026-109619 is about leftovers. When a fatal error or an execution timeout interrupts a request at the wrong point, some request-owned state (error state, session state, extension state) can survive in the worker process after the memory it points to has already been freed. The next request handled by that same worker can then read or free that stale pointer. The result is a use-after-free that has been demonstrated as full remote code execution against a real application on Apache with mod_php. One confirmed path runs through PHP’s session upload progress feature, which is enabled by default and has been validated against both mod_php and PHP-FPM. On PHP 8.5, the new fatal-error backtrace feature is another confirmed path.

The two bugs share a root cause and were reported independently by several teams, including researchers at Wiz, OpenAI, and Calif, which is a big part of why PHP coordinated one release for both.

Why this one is louder than usual

A few things made PHP2Shell messier than a normal security release, and they matter for how fast you need to move.

  • The disclosure leaked. The CVE identifiers started circulating on October 20, a day before the planned release, with an inflated CVSS score of 10.0 attached. One of the reporting firms also briefly posted a proof-of-concept video by mistake. PHP pulled the release forward a full day in response.
  • Patched builds appeared before the patch. A container image vendor published images containing the fix more than six hours before the coordinated release, which gave anyone watching a diff to work from.
  • Attackers were already probing. Amazon’s honeypot network recorded an exploitation attempt on October 17, four days before public disclosure. Cloudflare and other honeypot operators saw attempts on the morning of October 21, before the official release. By that evening, Arctic Wolf was reporting scanning and exploitation attempts that pulled down commodity Linux malware onto compromised hosts.
  • Appliance vendors are still assessing. Palo Alto Networks confirmed that all versions of PAN-OS and Panorama ship a vulnerable PHP, with fixed releases still pending as of October 21. Fortinet and Cisco were reviewing their product lines. Your firewall and your web server may both be on the list.

The PHP Foundation’s own post-mortem is unusually candid about this. The out-of-memory problem was first spotted during a funded external audit in 2024, and the fix then stalled, for far longer than it should have, because the volunteer security team could not reach consensus on which of several imperfect fixes to ship. The Foundation calls that “a structural failure” and has announced process changes and new paid security staff to prevent a repeat. That is good news for the long term. It does nothing for the servers that are exposed today.

Who is exposed

PHP’s guidance is blunt: treat every PHP installation that serves web requests as at risk. In practice the risk is tiered.

ConfigurationExposure
Apache with mod_phpHighest. CVE-2026-109618 is confirmed exploitable on default settings before any application code runs. CVE-2026-109619 is confirmed via both the session and backtrace paths. This is the default on many cPanel, XAMPP, and older Linux web hosts.
PHP-FPM (Nginx, Apache with proxy_fcgi, most modern hosts)Confirmed exploitable through application-level paths, including the default-on session upload progress feature.
LiteSpeed / LSAPILikely susceptible based on source analysis.
FrankenPHPLikely susceptible to CVE-2026-109618; no default-config path established yet for CVE-2026-109619.
Windows php.exe / php-cgi.exeBundled standalone binaries, often forgotten. Any that serve web traffic through IIS FastCGI are in scope.

The hard part is not the servers you know about. It is the PHP you forgot you were running:

  • The marketing site a contractor built on WordPress five years ago.
  • The cPanel or Plesk control panel on a hosting account. Plesk has already rebuilt its bundled PHP, including the end-of-life 7.4, 8.0, and 8.1 branches.
  • Internal tools: a phpMyAdmin install, a Nagios or Cacti dashboard, a ticketing system, a time-clock web app.
  • Docker containers built from an official php: base image that nobody has rebuilt since deployment.
  • Network and security appliances with a PHP web interface.
  • A developer’s XAMPP or WAMP install that is reachable from the office network.

Fixed versions

PHP branchSupport statusFixed version
8.5Active support8.5.12
8.4Active support8.4.27
8.3Security fixes only8.3.36
8.2Security fixes only8.2.35
8.1, 8.0, 7.4 and olderEnd of lifeNo release from the PHP project. The security team has published source patches for 7.4, 8.0, and 8.1; distributions and hosting vendors (Debian, Ubuntu, RHEL-family distributions such as AlmaLinux, and Plesk, among others) are shipping backports under their own version numbers.

If you are on an end-of-life branch, you are relying on your distribution or hosting vendor to backport the fix. Check with them. The volunteer-run Remi repository, popular on RHEL-family systems, said it would not have updates on release day, so if that is your PHP source you may need to move to distribution packages in the meantime.

How to find out what you’re running

On the server itself:

# Debian / Ubuntu
dpkg -l | grep php
apt changelog php8.2-fpm | head -40   # look for CVE-2026-109618

# RHEL / AlmaLinux / Rocky
rpm -qa | grep php
rpm -q php-cli --changelog | head -40

# Alpine (containers)
apk info | grep php

# Any platform
php -v

A distribution backport will keep an older version string but mention the CVE in its changelog, so do not rely on the version number alone on Debian or RHEL.

For a quick external check, Searchlight Cyber has released an open-source php2shell-scanner that tests whether a host is exposed. Like any active scanner, run it only against systems you own or have written authorization to test.

What to do, in order

1. Patch the internet-facing servers first. Anything serving PHP to the public gets the fixed build today, with a full restart of all PHP workers (systemctl restart php8.3-fpm, systemctl restart apache2, or a container rebuild from a patched base image). A reload is not enough if the old binary is still loaded.

2. Put a WAF in front of what you can’t patch yet. Cloudflare has deployed managed WAF rules for the known exploit vectors and made them available on every plan, including free. That buys time; it does not replace the patch, because the underlying bug is a memory issue that new request shapes can reach. If Cloudflare already fronts your site, the managed rules are a dashboard toggle, and as a Cloudflare partner it is something we can switch on for clients the same day.

3. Apply the stopgap settings on anything still unpatched. PHP is clear that no configuration change is a complete fix, but these close the confirmed paths:

; CVE-2026-109619: disable the default-on session upload progress feature
session.upload_progress.enabled = 0

; CVE-2026-109619, PHP 8.5 only: disable fatal error backtraces
fatal_error_backtraces = 0

; CVE-2026-109618: remove the memory_limit trigger.
; Set this in a php_admin_value / PHP_ADMIN_VALUE so nothing can override it.
memory_limit = -1

Then keep post_max_size small (PHP suggests 8M without uploads, 32M with), enforce request size limits at the web server or proxy, block multipart requests at the edge if the application does not use file uploads, and do not use RLIMIT_AS or RLIMIT_DATA to cap PHP, because those cause the exact allocation failures the bug depends on. On PHP-FPM, setting pm.max_requests = 1 removes the cross-request reuse that CVE-2026-109619 needs, if your traffic can tolerate it. Restart every worker after each change.

4. Rebuild containers. A docker pull of the patched base image followed by a rebuild. Images that were built from php:8.3-fpm on a Tuesday last spring still carry the old engine.

5. Check your appliances. Review Palo Alto, Fortinet, and Cisco advisories for anything with a web management interface, and make sure that interface is not reachable from the internet in the first place.

6. Move off end-of-life PHP. A backport from your distribution gets you past this week. It does not get you a supported engine for the next vulnerability. If you are on 7.4 or 8.0, plan the upgrade.

7. Hunt for signs you were already hit. The window between the leak and the patch was short, but not zero. Look for web shells (new .php files in upload directories, wp-content, or /tmp), the web server user (www-data, apache, nobody) spawning shells or wget/curl, unexpected outbound connections from the web server, new cron entries or systemd units, and unfamiliar ELF binaries in writable directories. If you find any of that, treat the host as compromised and stop reading this post.

What this looks like from a monitored environment

This is the kind of event a managed stack exists for. The RMM already knows which servers carry a PHP package and which version, so the inventory question is answered in minutes rather than by email. Cloudflare’s managed WAF rules go on at the edge for the zones it fronts. And the SOC watches for the post-exploitation behavior Arctic Wolf and others have reported: a PHP or Apache worker spawning a shell, outbound downloads from the web server account, and new persistence on Linux hosts.

The honest limitation is the same one PHP named: a server with no endpoint monitoring, on the public internet, running a PHP that nobody has inventoried, is the one most likely to be quietly compromised and stay that way. The flaw does not need a phishing email or a bad password. It needs an HTTP request.

If you are not sure what PHP you are running, or you have a vendor-managed site you cannot patch yourself, that is a reasonable thing to ask us about. The inventory is the step most organizations skip, and it is the one that decides how this week goes.

Sources

Trusted by dozens of businesses