PHP2Shell Explained: Which PHP Stacks Are Exposed and What to Do Now
Two critical bugs in the PHP interpreter can let an unauthenticated request run code. Which stacks are exposed, what the "exploited" reports really show, and a patch, restart and hunt checklist.
October 25, 2026
Most PHP security bugs live in a framework, a plugin or your own code, but this one lives in the interpreter. The PHP2Shell vulnerability is a pair of flaws, CVE-2026-109618 and CVE-2026-109619, that can let an unauthenticated request run code on a PHP server. On Apache mod_php, that can happen before any of your application code runs.
PHP fixed both on 21 October 2026. Here's what happened, who's exposed, what the "exploited" headlines really show, and the checklist I'd run this week.
What happened, from leak to patch
The bugs were found by Calif, OpenAI and Wiz. Calif's timeline puts the first out-of-memory bug on 1 August 2026 and the report to PHP on 11 August. A working RCE proof of concept was shared on 14 August, PHP confirmed it the next day, and the second bug was reported on 21 August.
Calif says the initial discovery used no special harness and only generally available models, which is worth knowing if you follow where AI agents are heading as working tools.
Disclosure was planned for 22 October, and it didn't hold. Details leaked on social media on 20 October, PHP posted a notice about an upcoming critical release, and watchTowr confirmed the bugs publicly the same day. Fixes shipped on 21 October at 14:00 UTC.
The fixed releases are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, announced in PHP's security advisory. PHP's security team scores both CVEs 9.2 Critical on CVSS v4.0. NVD's own v3.1 scores split them: 9.8 for CVE-2026-109618 and 8.1 for CVE-2026-109619.
Before the patches were out, Cloudflare's CTO said the company was already seeing early attacks and had deployed temporary WAF rules.

How the PHP2Shell vulnerability works
Both bugs come down to PHP trusting state after something has already gone wrong.
CVE-2026-109618: corruption on out-of-memory. When PHP runs out of memory, it bails out with longjmp(). If that happens while PHP is still building the request data, the cleanup at the end of the request works with data that was never finished. The GHSA-w8hw-w9fx-j79w advisory says crafted multipart requests can get there, because some of the usual size and count limits on uploads can be sidestepped.
CVE-2026-109619: stale state across requests. PHP workers that serve request after request hold on to some global state, such as error, session, object and extension data. When a request dies from a fatal error, a timeout or an OOM, that state can be left referring to memory the request already released.
The next request on that worker never gets a clean start: code that runs early, like INI diagnostics or session upload progress, reaches into memory the previous request gave back. That's a use-after-free (CWE-416), and per the GHSA-6wmf-4rv5-p3rp advisory, both steps have to hit the same worker.
The fix for the first bug: PHP no longer jumps out mid-operation when memory runs out. It now waits for a safe point in the engine before stopping, and if memory keeps climbing past a higher limit, it exits immediately with _exit().
Turning off error output with error_reporting, display_errors, log_errors or @ doesn't stop CVE-2026-109619 from touching the freed memory. Quieter logs are not a fix.
flowchart TB
A(["Request reaches PHP worker"])
B{"What goes wrong?"}
C["longjmp() bails out"]
D["Request data half set up"]
E["Shutdown uses invalid state"]
F["Worker keeps stale state"]
G["Same worker, next request"]
H["Early code reads freed memory"]
I["Possible code execution"]
A e1@--> B
B e2@-->|"out of memory mid-parse"| C
C e3@--> D
D e4@--> E
E e5@--> I
B -->|"fatal error, timeout or OOM"| F
F --> G
G --> H
H -->|"use-after-free"| I
e1@{ animate: true }
e2@{ animate: true }
e3@{ animate: true }
e4@{ animate: true }
e5@{ animate: true }
%% walkthrough "CVE-2026-109618: OOM corruption": A > B > C > D > E > I
%% walkthrough "CVE-2026-109619: stale state": A > B > F > G > H > I
Is your stack exposed? mod_php, FPM, FrankenPHP and the rest
If PHP serves web requests, assume yes until you've patched. Rapid7 puts PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed in scope.
The advisories say what's actually been shown:
- Apache mod_php is confirmed exploitable. Researchers got full code execution through CVE-2026-109618 over plain HTTP on a normal prefork setup with default input and memory limits, and reached CVE-2026-109619 two ways: PHP 8.5's
fatal_error_backtracesand the session code. - PHP-FPM is conditionally exposed. The session route to CVE-2026-109619 worked against an ordinary dynamic pool; the advisories don't show a full FPM exploit for CVE-2026-109618.
- FrankenPHP and LSAPI are likely susceptible, based on source analysis.
- CLI isn't addressed by the advisories, so I won't call it safe or unsafe.
PHP rates mod_php the highest risk. My reading: mod_php runs inside every Apache worker and parses the body before your app, so no app-specific endpoint is needed. That suggests moving to FPM behind frontend request limits lowers the exposure without removing it.
| Stack | Status | What it rests on |
|---|---|---|
| Apache mod_php | Confirmed | Advisories: full RCE for CVE-2026-109618 over HTTP with default limits; CVE-2026-109619 via fatal_error_backtraces (8.5) and the session path |
| PHP-FPM | Conditional | Advisories: CVE-2026-109619 session RCE validated on a normal dynamic pool; no full exploit for CVE-2026-109618 |
| FrankenPHP | Likely | Advisories: source analysis |
| LSAPI (LiteSpeed) | Likely | Advisories: source analysis |
| php-cgi | In scope | Rapid7 scope list |
| CLI | Not addressed | Advisories are silent; don't assume either way |
What's been shown so far, stack by stack.
Exploited or not? Reading the honeypot reports
Amazon Threat Intelligence found a PHP2Shell exploitation attempt in its MadPot telemetry dated 17 October, four days before the fix. It says the earliest PoC exploits appeared around 02:00 UTC on 21 October, twelve hours before the embargo lifted. watchTowr reports exploitation since 21 October through its Attacker Eye network.
MadPot and Attacker Eye are both honeypots: decoy systems that record attack traffic. A hit shows attackers are trying, not that a real system was breached. Amazon itself says it's unclear whether any of these attempts would have succeeded against real-world systems.
Rapid7 reports exploitation attempts but no exploitation in the wild, and says each public PoC works only for one OS, PHP version and web server combination. Canada's Cyber Centre has identified no active exploitation, while warning that can change quickly. CISA's SSVC triage entry in NVD, dated 21 October, says exploitation: none.
So my summary as of 25 October: attack and exploitation attempts have been seen on honeypots since 17 October. No confirmed compromise of a real system is publicly documented (my reading across the sources, not a claim any one makes), and neither CVE is in CISA's Known Exploited Vulnerabilities (KEV) catalog as of version 2026.10.23.
One more trap: JFrog found fake PHP2Shell PoCs on GitHub carrying prank malware.

Why it matters for PHP developers and ops teams
Both advisories list every release before 8.2.35, 8.3.36, 8.4.27 and 8.5.12 as affected, with no lower bound, and that includes end-of-life branches. Calif says the earliest affected path it found dates to PHP 5.4.0.
PHP 8.1 and older no longer get updates from the PHP project. Its security team did publish minimal source backports for PHP 7.4, 8.0 and 8.1. watchTowr says PHP 7.3 and older, including PHP 5, have no fix, and that Linux distributions and LTS vendors got patches early.
And a lot of internet-facing PHP is old. Mallory, using Shodan data from 20 October, counts about 2.24 million internet-facing hosts advertising PHP. Among hosts that show a version, 883,717 of about 1.5 million (59%) run a branch with no official fixed release.
Those are hosts advertising PHP, not proven exploitable ones, and other counts measure services or IPs.
PHP also hides inside products you don't think of as PHP. Palo Alto Networks lists PAN-OS 12.2, 12.1, 11.2, 11.1 and 10.2 builds as affected, with most hotfix ETAs between 27 and 30 October. If you run appliances, read your vendors' advisories too.

What I'd do this week: patch, restart, hunt
PHP puts it plainly, and I agree: "There are no complete mitigations, updating is the only safe choice."
- Find the PHP that actually serves each app. As Datadog Security Labs points out, the
php -von your CLI may not be the runtime behind your site, so check containers and bundled runtimes. The UK NCSC adds that all versions may be affected, so don't limit discovery to outdated ones. - Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or to a vendor package that includes both patches. Datadog notes that distro packages may backport the fixes without changing the version number, so check the package changelog, not just the version.
- Restart every PHP worker and rebuild container images. As Datadog stresses, a patched package on disk does nothing for a worker still running the old code.
- If you can't patch today, narrow the paths.
- Put
memory_limit=-1,session.upload_progress.enabled=0and, on 8.5,fatal_error_backtraces=0in php.ini, the FPM pool or the Apache config, sinceini_set()and.user.inikick in too late. Restart workers afterwards. PHP says these close only the confirmed paths. - At the frontend, cap request size, multipart parts, headers per part and nesting depth, and refuse multipart where you don't need it. Don't use
RLIMIT_ASorRLIMIT_DATA, and don't rely on cgroup limits alone. - If even that takes too long, NCSC says to consider taking the system offline.
- Put
- Hunt from 17 October, not 21. Datadog's signs include OOM fatals during initialization at "Unknown on line 0", Apache AH00052 segfaults, multipart uploads with unused PHPSESSID or PHP_SESSION_UPLOAD_PROGRESS fields, deeply nested field names, filenames containing
<?phpor|O:, and long or binary PHPSESSID values inSet-Cookieheaders. The strongest sign of all is an Apache or PHP worker launching a shell or a download tool.
Start the investigation from the earliest known attack, not from the day the headlines landed.
That's Amazon's advice, in my words. Rapid7 adds: "The absence of relevant log entries is not proof that an installation is safe." It's the same instinct as how I read another production break-in as an architecture bug: assume the attempt reached you, then check what it could touch.
On WAFs: AWS says customers on the default AWS WAF managed rule version are protected automatically, while pinned versions must update. Treat WAF rules as buying time, not the fix. Keep session.upload_progress.enabled=0 in mind too: PHP's 23 October informational advisory suggests it for a narrower session bug, CVE-2026-115560, until the next regular bugfix release.
flowchart TB
A(["Find the serving PHP"])
B{"Can you patch now?"}
C["Update to fixed release"]
D["Restart workers, rebuild images"]
E["Hunt from 17 October"]
F["Set interim settings, restart"]
G["Bound requests at frontend"]
H{"Patch coming soon?"}
I["Consider taking it offline"]
A e1@--> B
B e2@-->|"yes"| C
C e3@--> D
D e4@--> E
B -->|"no"| F
F --> G
G --> H
H -->|"yes"| C
H -->|"too long"| I
I --> E
e1@{ animate: true }
e2@{ animate: true }
e3@{ animate: true }
e4@{ animate: true }
%% walkthrough "mod_php server, distro update available": A > B > C > D > E
%% walkthrough "FPM pool, package lands tomorrow": A > B > F > G > H > C > D > E
%% walkthrough "End-of-life app, no fix in sight": A > B > F > G > H > I > E
Takeaways
- PHP2Shell is two bugs in the interpreter itself, rated 9.2 Critical by PHP, fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35.
- Rapid7 puts every PHP that serves web requests in scope. mod_php is the highest risk; FPM is confirmed for one path, conditional for the other.
- Patching isn't done until every worker restarts and every image is rebuilt. Check the runtime that serves the app, not the CLI.
- "Exploited" so far means honeypot traffic since 17 October, with no documented real-system compromise and no KEV listing as of 25 October.
- Hunt back to 17 October, and don't read quiet logs as a clean bill of health.

