
Reading through the PHP2Shell advisories last week, what stayed with me was not the CVSS score. It was the attack surface. An attacker needs no login, no account and no permissions. Knowing the address of a website is enough to start. And the bug is not in WordPress, Laravel or your own code. It is in PHP itself.
This post is my attempt to separate the signal from the noise: what PHP2Shell actually is, what it can do, what damage has really been recorded so far, and what I think engineering teams should do, this week and over the next few years. Every number links to its source. Facts are as of October 26, 2026.
What PHP2Shell is
PHP2Shell is the name researchers gave to two vulnerabilities in the PHP engine, CVE-2026-109618 (“RCE via OOM corruption”) and CVE-2026-109619 (“RCE via stale global state”). Both are rated 9.2 (critical) on CVSS 4.0. The vulnerable code goes back to PHP 5.4, released in 2012, and was fixed in PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 on October 21, 2026.
Both bugs live in the two places almost every request touches: memory management and error handling. In plain terms:
- CVE-2026-109618. When a request hits PHP’s
memory_limitat exactly the wrong moment, PHP aborts while some internal request data is only half built. The cleanup code that runs afterwards trusts that data as if it were valid. According to the advisory, the out-of-memory condition can be reached by the request body itself, before any application code runs. - CVE-2026-109619. PHP workers live across many requests. Some global state that points into one request’s memory can survive after that memory is freed, when a fatal error interrupts the normal reset. A later request handled by the same worker can then act on memory that no longer belongs to it, a classic use-after-free (advisory).
Wiz Research, one of the teams that found the bugs, also showed that one path leaks worker memory back to the client, memory that may hold passwords, session tokens, API keys and certificates from other users’ requests. That detail matters later, when we talk about what “fixed” really means.
Why “every PHP site” is true, and why mod_php is the worst case
The flaw is in the engine, so the application on top does not matter. Wiz demonstrated it against the stock container images of WordPress, Drupal and Joomla, and notes that even a “Hello World” app on an affected PHP version can be vulnerable. Apache or Nginx makes no difference either. What matters is how PHP is attached to the web server (the SAPI):
How PHP runs | Exposure according to the PHP advisories |
|---|---|
Apache mod_php | Highest. Apache runs request shutdown even when startup failed, so the attack can complete before any application code runs. Full RCE was demonstrated with default settings. |
PHP-FPM (Nginx, Apache proxy) | Affected. FPM kills a child whose startup failed, which breaks the simplest path, but RCE was confirmed through application-level code paths. |
FrankenPHP, LiteSpeed (LSAPI) | Likely affected according to source analysis; not fully validated. |
PHP CLI, cron jobs | Not the target: the attack needs PHP to serve web requests. |
This is why I consider mod_php the most dangerous setup. PHP runs inside the Apache process itself. Whoever takes over PHP is running code as the web server, with every site and secret that process can reach. With FPM there is at least a process boundary and a pool you can isolate.
“One request is enough”? Not quite
The first headlines said a single request could take a server. The advisories are more precise, and the difference is useful for defenders. No authentication is needed, that part is true. But the confirmed attacks chain several requests that must land on the same PHP worker, and reliability depends on the PHP build, extensions and memory layout. Sansec reported on October 22 that the public proof-of-concept code did not work against a default PHP installation, and VulnCheck found that none of the public code defeated ASLR on x86-64 on its own.
None of that is a reason to relax. Wiz and Calif have working exploits, the bugs are real, and attackers have the same AI tools the researchers used. It is a reason to patch calmly and investigate properly instead of panicking.
What an attacker gets
- Code execution as the web worker account. From there: read the database credentials in the config file, dump user data, plant a webshell for later, or deface the site. The NSA warned that such flaws “often provide a direct path to the server’s file system or database”.
- Secrets from memory, without full RCE. The memory-disclosure path can expose data belonging to other users’ requests: session tokens, passwords, API keys.
- Cheap infrastructure. Compromised servers become crypto miners, proxies or DDoS nodes. The first payload Sophos caught was a Mirai botnet variant called “Potassium”, built for DDoS.
- Appliances, not just websites. PHP also runs inside products that never advertise it. Palo Alto Networks confirmed that PAN-OS and Panorama management interfaces are affected, and Cisco listed Expressway and Duo Access Gateway.
The damage recorded so far
This is where I want to be careful, because “70% of the internet” makes a good headline and a poor damage estimate. Here is what has actually been measured:
Metric | Figure | Source |
|---|---|---|
Websites using PHP (of those with a known server-side language) | 69.2% | |
PHP sites still on version 7 or older (no official PHP release) | 34.5% | |
Internet-facing hosts with a visible PHP version that were unpatched on Oct 21 | ≈1.57 million of 1.58 million | |
Hosts announcing an end-of-life PHP version (5.4–8.1) | ≈758,000 of 1.1 million | |
First exploitation attempt seen (honeypot) | Oct 17, four days before disclosure | |
Attempts on Cloudflare’s network | Thousands before the announcement, tens of thousands 45 min after, millions within a day |
The most visible cost so far is not stolen data but precautionary shutdowns. Following advice from the NSA, the UK NCSC and CERT-EU, Finland temporarily shut its government’s public web services, and Dutch agencies, the Tweede Kamer and parts of Wikimedia went offline (BBC). Council websites in Edinburgh, Bristol and Oxford and the Paris police prefecture site went dark too (The Guardian). In Japan, Prime Minister Sanae Takaichi asked on X for public websites to be checked that same night, and the National Cybersecurity Office said temporarily stopping a site was a valid option if patching could not be done quickly (INTERNET Watch).
On confirmed break-ins, the honest answer is that public evidence is still thin. watchTowr saw exploitation of both CVEs in its honeypots, but Sophos retracted an early report of a successful compromise and, as of October 22, had no evidence of a successful compromise. Two cautions, though. Amazon’s honeypot was probed on October 17, so compromise may predate the advisory. And JPCERT/CC warns that some attack paths may leave no trace in the logs. “No incident reported” is not the same as “no incident”.
Why the leak was the scariest part
In my view, the most frightening part of PHP2Shell is not the bug but how fast it escaped. The coordinated disclosure worked until two days before the release date. Then, on October 20 at around 15:00 UTC, the CVE IDs started circulating online. PHP moved the release forward by a day. A few hours later, one of the reporting firms mistakenly published a proof-of-concept video. On the morning of October 21, a vendor that had the patch in advance published fixed builds more than six hours early, which let anyone diff the fix (PHP Foundation, timeline).

Amazon’s conclusion is the one every security lead should pin to the wall: “AI-assisted analysis makes it cheaper to turn a patch diff or advisory into a working exploit.” A 7-day or 30-day patch SLA assumes a delay that no longer exists.
What to do now
1. Patch, then prove the patch is live
Upgrade to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35. For 7.4, 8.0 and 8.1 there are no official builds, only source backports, so use a maintained package: Ondřej Surý’s repositories for Debian/Ubuntu, Remi’s for RHEL-family, Ubuntu Pro, CloudLinux, TuxCare or Zend (Sansec keeps the list). For 7.3 and older there is no fix at all: upgrade.
Two traps I have seen teams fall into: checking the CLI version instead of the one serving web traffic, and forgetting to restart workers.
# 1. The version that actually serves web requests (the CLI can differ)
# Put a temporary phpinfo() page behind auth, or check the FPM binary:
php-fpm8.3 -v # adjust to your version
apachectl -M | grep php # is mod_php loaded at all?
# 2. Distribution packages keep the old version number after a backport,
# so look for the CVE in the changelog instead
zgrep CVE-2026-109618 /usr/share/doc/php8.3-common/changelog.Debian.gz # Debian/Ubuntu
rpm -q --changelog php-common | grep CVE-2026-109618 # RHEL/Alma/Rocky
# 3. Restart every worker, or the old code keeps running in memory
sudo systemctl restart php8.3-fpm # or: sudo systemctl restart apache22. If you cannot patch today
The PHP team is explicit that updating is the only complete mitigation. Stopgaps only buy time:
- Put the site behind a WAF. Cloudflare says its free and paid WAF customers were protected by default from October 21, 03:02 UTC against known exploit attempts, as long as the site uses PHP’s default upload-progress field name.
- Turn off session upload progress, and on PHP 8.5 fatal error backtraces. Each closes one demonstrated path, not all of them.
- Limit request size, multipart parts and nesting depth at the reverse proxy. If the app never accepts uploads, reject multipart requests at the edge.
- If none of that is possible and the site holds sensitive data, take it offline until it is patched, as the NCSC advised.
; Temporary, partial stopgap from the PHP advisories. Patching is the only fix.
; PHP-FPM reads its pool config, not the CLI php.ini:
; /etc/php/8.3/fpm/pool.d/www.conf
php_admin_flag[session.upload_progress.enabled] = off
; PHP 8.5 only:
php_admin_flag[fatal_error_backtraces] = off3. Hunt for compromise, starting from October 17
Patching closes the door; it does not tell you whether someone walked in first. JPCERT/CC’s three indicators are a good starting point: abnormally long or malformed PHPSESSID cookies in past responses; suspicious multipart/form-data requests followed by memory-limit errors or HTTP 500s; and PHP workers crashing or restarting unexpectedly. Add the usual post-exploitation checks: the web server spawning a shell, unknown PHP files in web roots, new cron jobs and unexplained outbound connections.
Rotate secrets on every exposed host, even if you find nothing. Because one path leaks memory, a patched server can still have leaked database passwords, API keys and session signing keys before the patch. The patch does not un-leak them.

The long-term fixes
I said on Facebook that there is no silver bullet, only defense and damage limitation. After the research for this post, I would put it in five concrete moves:
- Know where you run PHP. Forescout’s Sai Molige put it well: treat “how quickly can we identify where we run X?” as a capability measured separately from patching speed. That includes the PHP inside appliances, control panels and vendor products.
- Automate updates and keep the patch window in hours. Unattended security updates for distro packages, base images rebuilt and redeployed by pipeline, and a rehearsed emergency runbook. Amazon’s advice is to measure critical patch timelines in hours.
- Leave mod_php and end-of-life versions behind. Move to PHP-FPM with one pool per site, a separate user per pool, and a supported PHP branch. W3Techs says 34.5% of PHP sites still run version 7 or older, none of which gets an official PHP release any more.
- Assume the web tier will be breached. Run the worker with least privilege, block outbound traffic it does not need, keep secrets out of the web root, and segment it from internal systems. Monitor behavior in real time (a web server spawning
shis suspicious whatever the CVE), because the first exploitation often comes before signatures exist. - Use AI on your own code before attackers do. The PHP project itself now scans its code with AI tools, including Anthropic’s Claude Mythos and OpenAI’s tooling. Teams can put the same kind of AI review into their CI for their own code and dependencies.
The bigger picture: AI has lowered the cost of attack
The PHP2Shell bugs had been hiding in plain sight. PHP’s own developer saw the first signs during a 2024 audit, but no one could show a practical exploit, the team could not agree on a fix, and the work stalled for months, a delay the PHP Foundation itself calls a structural failure. What changed in 2026 was the tooling. Wiz writes that with frontier models, “a single researcher completed in a week what previously would have taken a world-class team months of work”.
PHP2Shell was not alone. On the same day, Node.js fixed CVE-2026-111497, an out-of-bounds write in the bundled Brotli decoder that can lead to remote code execution, reported by OpenAI’s Codex Security team. The PHP security team says it has published 15 CVEs since July 1 and worked through more than 100 invalid reports, as AI multiplies the volume. My expectation: every memory-unsafe component that sits close to untrusted input (language runtimes, compression and image libraries, web servers, device firmware) will see the same pressure. Old bugs once dismissed as “too hard to exploit” are back on the table.
In my Facebook post I also wrote that the damage would probably stay economic, because classified systems are air-gapped and do not run PHP. I still think that is mostly right. But PHP2Shell shows the line is thinner than it looks: PHP sits inside the management interface of firewalls that protect sensitive networks. The weakest link is often the box you bought to be the strongest one.
My takeaway. There is no permanent fix for a world in which finding and weaponizing bugs keeps getting cheaper. There is only a faster loop: know what you run, patch in hours, assume breach, watch in real time, and use the same AI on your own code that attackers will use on it.
Need help with this?
Explore the iPlus Solution services most relevant to this article.



