Section 01Executive Summary
On 21 October 2026 the PHP project shipped emergency fixes for two critical flaws, CVE-2026-109618 and CVE-2026-109619, that let an unauthenticated attacker run code on a web server by sending requests PHP processes before any application code runs.[1][2][6][26] Both are rated CVSS v4.0 9.2.[1][2] The fix was planned for 22 October; the identifiers leaked on 20 October and the release was pulled forward a day.[7][15]
Most coverage so far repeats the headline, the version numbers and “patch now”. That advice is right, but it leaves the interesting questions unanswered. How does running out of memory become code execution? Why do PHP and the researchers describe the two CVEs differently? What does each way of running PHP change? Which of the mitigations people reach for first do not work at all? How much of the exploitation news is evidence and how much is claim? This report works through those questions, with a source for each statement.
The core idea fits in two sentences. PHP gives every request a block of memory and, when a request dies in the middle of its work, jumps out through an emergency exit that skips the tidy-up steps.[1][11] If a pointer to that memory was already published, or a structure was only half built, something later in the same worker process trusts what is left behind.[1][2][3]
Key takeaways
- 01This is one bug class showing up in several places, not two isolated typos.
Both advisories describe state that is half-built or dangling when a request is interrupted. The discoverers found the same “publish, do fallible work, commit” pattern at several points in the engine, which is why the fix is a change to how PHP fails rather than a one-line patch.[1][2][3]
- 02The hardening reflexes administrators reach for first mostly do not work.
Hiding errors, setting values with
ini_set()or.user.ini, process address-space limits and container memory limits either act too late or push PHP onto the vulnerable path. PHP states that there is no complete generic configuration mitigation.[2][1][6] - 03Patch and restart is the only complete fix, and the fix changes how PHP handles out-of-memory.
The patch removes the emergency jump on out-of-memory and replaces it with a delayed soft stop and an immediate hard stop at a higher threshold. After patching, every worker must be restarted and the binary that actually serves requests must be verified.[1][9]
- 04Apache mod_php is the worst case; PHP-FPM is conditional, not safe.
Under mod_php the demonstrated attack runs before application code. FPM kills its child process on a failed startup, which blocks that one sequence, but the PHP Foundation says code execution was confirmed on FPM through application-level code paths, and session-lifecycle execution was validated under suitable application conditions.[1][2][3][6][28]
- 05
- 06Exploitation is under way, and it began before the patch.
Amazon says its honeypots saw an exploitation attempt on 17 October, four days before disclosure, and that PHP2Shell is now broadly exploited. Cloudflare’s chief executive says attempts rose from thousands in the ten hours before the announcement to millions by the next morning. CISA said when it published that it had not observed exploitation, and no compromise had been publicly confirmed, so the open question is how many attempts succeeded.[38][49][37]
- 07AI shortened the path from idea to exploit, and the disclosure process broke under it.
Both discovering teams credit AI models for variant analysis and for adapting exploits across PHP versions; these are vendor-reported claims, but they match each other. The embargo then failed three ways within a day: leaked identifiers, an accidentally published demonstration video, and a distributor that released patched images more than six hours early.[3][4][28][31]
- 08Governments treated it as an emergency and said so in public.
The prime ministers of Japan and the Netherlands, Canada’s minister of artificial intelligence and digital innovation, the US National Security Agency, the UK National Cyber Security Centre, CISA and CERT-EU all told organisations to prepare, patch immediately or take unpatchable systems offline, and government sites went dark in at least nine countries.[44][58][51][45][46][37][29][17]
Section 02PHP2Shell at a Glance
Three patterns stand out. First, the gap between leak and patch was about a day, and attack traffic reportedly started inside it: a defender’s usual “wait for the patch, then schedule it” rhythm did not apply.[5][14][24] At 07:41 UTC on release day a distributor published patched images more than six hours before the coordinated release, a fact both it and the PHP Foundation confirm.[28][31] Second, the response was availability-first. Governments and large sites chose to switch services off rather than run exposed, which is unusual and tells you how the risk was read.[17][5] Third, the exploitation picture moved quickly: some vendors saw nothing while others described attacks at scale, the PHP team found no functional exploit at release, and by 22 October Amazon reported an attempt dating to 17 October while Cloudflare’s chief executive reported millions of attempts.[14][8][11][7][38][49] Section 11 sets out each claim and its source.
Section 03Why It Matters: Exposure and Blast Radius
Estimates of PHP’s share of the web range from about 70% to nearly 75% of sites whose server-side language is known.[15][16][4] That figure is easy to quote and hard to act on, because the exposure sits in many different places. The vulnerabilities are in the PHP engine, so patching WordPress, Drupal or Magento does not fix them and a hardened custom application is as exposed as a default install.[4][16]
CMS and e-commerce
WordPress, Drupal, Joomla and Magento were named by the researchers; Sansec singles out Magento, Shopware and WooCommerce stores as a particular concern.[3][4][16]
Control panels and shared hosting
cPanel and Plesk bundle PHP, and shared hosts run many customers’ code on one engine. Customers cannot patch what the host controls.[8]
Appliances and Windows software
Vendor appliances and some Windows applications ship their own php.exe or php-cgi.exe, on the vendor’s update schedule rather than yours.[8]
Intranets and supplier-connected apps
Time-tracking tools, old CRMs and intranets can be reachable through routing mistakes or supplier connections even when they look internal.[16]
Containers and managed runtimes
Google Cloud says its own platform is not vulnerable, but customer workloads on it may be; some runtimes patch automatically and others need a redeploy.[10]
What was actually demonstrated
Calif reports unauthenticated remote code execution against a long list of PHP applications: WordPress, Drupal, Joomla, MediaWiki, Roundcube, Magento, phpMyAdmin, Nextcloud, Laravel and Symfony, with WHMCS in some cases, and arbitrary-script code execution in some configurations. It says the exploitable paths work under default settings.[3] Wiz tested the stock wordpress:latest, drupal:latest and joomla:latest container images and reports unauthenticated code execution against each, plus a separate memory-disclosure path that does not need code execution at all.[4] Both are the discoverers’ own claims, and they agree with each other.
Fig. 1 — Who gets a fix, and from where
Patch coverage by PHP branch · fixed versions shown under the green blocks
Sources: PHP advisories and Tenable for branch coverage;[1][2][7] Google Cloud for the managed-runtime note.[10] Version 5.4.0 is the earliest affected code path per Calif; older branches were not analysed.[3]
Two practical traps follow. Distribution builds often keep an older upstream version number while carrying the fix, so php -v alone can mislead; the vendor advisory is the reference.[9] And the PHP binary on your command-line path is often not the one serving requests, so a host can look patched while its web workers are not.[9] Linux distributions and long-term-support vendors received patches before the public release, and advisories already exist for Red Hat, Gentoo, Fedora and Ubuntu.[9]
How big is the unpatched tail?
Counts of exposed PHP are estimates from different methods. VulnCheck found PHP on 2,608,039 internet-facing hosts, over 700,000 of them on 3.x to 7.3, about 400,000 on 7.4, 8.0 or 8.1 and about 403,000 on the supported 8.2 to 8.5 branches.[38] A VirusTotal analysis relayed by The Record found 5.1 million IP addresses running PHP, at least 758,000 of them on end-of-life versions and 85,000 on the latest pre-patch releases; the article stresses these show internet footprint, not confirmed vulnerable systems.[32] Zafran counts about 1.5 million internet-facing hosts advertising a PHP version, with more than half on 8.1 or older.[35] Cisco Talos is reported to estimate that roughly half of vulnerable PHP systems may never receive a patch.[32] A live blog adds that about 18% of WordPress sites and 24% of Joomla sites reportedly run 8.1 or older, a figure not traced to a primary source. AhnLab estimates that about 110,000 Korean hosts ran vulnerable versions before the patches, the sixth-highest count worldwide.[40][34] Earlier estimates put potentially vulnerable exposed hosts between 1.3 million and 1.9 million, from two different methods that were never reconciled.[7] The numbers disagree on size but agree on direction: a large share of exposed PHP sits on branches that get no upstream fix.
Section 04The Engine in One Page
A PHP worker is a long-lived process that handles request after request. How it is wired to the web server is called its SAPI: Apache’s mod_php runs PHP inside the Apache worker; PHP-FPM keeps a pool of child processes behind nginx or Apache; php-cgi, FrankenPHP and LiteSpeed’s LSAPI are other arrangements.[1][2] For every request the worker runs startup (apply per-request settings, parse the incoming body), then your application, then shutdown (clean up).[2] Startup and shutdown are engine code that you did not write and cannot patch.
Fig. 2 — Where PHP2Shell lives: before your code
The request path through a PHP worker · the red box is the vulnerable window
Startup parses multipart bodies, including the session upload-progress logic, before the application runs.[2][5] php_request_startup() is named in the advisory as part of the early path.[2]
Each request gets its own heap, and PHP frees that heap when the request ends.[2] A configurable ceiling, memory_limit, stops one request from eating the machine. When an allocation would cross it, PHP does not return an error to the caller. It performs a bailout, a longjmp() to an error boundary, which is fast but skips every step between the failure and that boundary.[1][11]
The pattern behind both bugs
Calif’s research reduced the problem to a pattern worth memorising: state is published or destroyed, fallible work follows, and a fatal error skips the commit or rollback step.[3] If PHP stores a pointer in a global before the risky part, the cleanup that would clear it never runs when the risky part dies. If it increments a counter before allocating the thing the counter describes, teardown later trusts a count that is ahead of reality.[3]
Fig. 3 — Publish, fail, skip the reset
The vulnerable pattern in three rows
Pattern as described by Calif and the PHP advisories.[1][2][3] The “global” can be many things; Section 6 lists the families the advisory names.
Two properties make this attractive to an attacker. The ceiling is predictable: the default heap limit is 128 MiB, so a request can be shaped to fail at a chosen moment.[3] And the dangerous parsing happens early. Sansec notes that every known trigger is a multipart/form-data request, which PHP parses before the application can say no.[5][3]
Section 05CVE-2026-109618: When Running Out of Memory Is the Attack
PHP’s advisory describes the mechanism in three sentences. In some contexts request memory is briefly reachable before it is fully initialised. If an allocation fails inside that window, the bailout leaves the structure half-built. Request shutdown then reads or branches on that memory, and the failing allocation does not have to be related to it.[1]
How a request under the limits still exhausts memory
The obvious defence, a small post_max_size, turns out to be weaker than it looks. The advisory and Calif list several ways to push memory use past memory_limit with a body that looks small:[1][3]
| Technique | Why the size limit does not stop it | Source |
|---|---|---|
| Multipart body with no usable declared length | The limit is checked against the declared length. Chunked HTTP/1.1, length-less HTTP/2 and decompression filters let decoded data keep arriving after the check. | [1][3] |
| Many headers inside one part | There is no cap on part headers, and their in-memory representation is far larger than on the wire. | [1] |
| Empty file fields | Parts with an empty filename carry no data and do not count toward max_file_uploads, yet each still creates several $_FILES entries; nested field names multiply that. | [1][3] |
| Application-specific inputs | Any feature that allocates in proportion to attacker input can reach the limit; the advisory says these also count. | [1] |
Calif adds a detail about one interruption point: a hash-table insert increments its counters before allocating the key, so a failure at that moment leaves a visible but uninitialised entry that teardown later processes.[3]
Why the SAPI decides the outcome
Fig. 4 — The same fatal, two different outcomes
CVE-2026-109618 by SAPI · what happens after startup fails
mod_php: PHP validated code execution over HTTP with default limits and multiple prefork workers.[1] FPM: the startup-failure sequence is blocked. The advisory notes no complete FPM exploit of that sequence, while the Foundation’s postmortem says RCE was confirmed on FPM through application-level code paths.[1][6][28]
Under mod_php, request shutdown runs even when startup failed, so the engine tidies up a structure that was never finished, before any of your code has had a chance to refuse the request.[1] Under PHP-FPM, a failed startup makes the child exit and the damaged state disappears with it.[1][3] Calif’s FPM route therefore needs a fatal after a successful start, aimed at the bookkeeping used when decoding serialized data; it reports application-dependent code execution there too, and the PHP Foundation’s postmortem says RCE was confirmed on FPM through application-level code paths.[3][28]
What the patch changes
The fix removes the longjmp() on out-of-memory. PHP now raises a delayed “soft” out-of-memory condition at the next safe point in the virtual machine, which lets it stop gracefully, and an immediate “hard” stop through _exit() if usage reaches a second, higher threshold. Shutdown no longer sees invalid state and normal memory_limit enforcement is kept.[1] One operational consequence is worth testing before you rely on it: at the hard threshold the worker can end immediately, skipping shutdown handlers.[9]
Impact. Unauthenticated code execution with the privileges of the web worker account, not necessarily root. Reliability depends on the PHP build, extensions, front-end behaviour and memory layout, which is why the CVSS vector rates attack complexity high.[1][6][11]
Section 06CVE-2026-109619: One Request Poisons the Next
The second CVE is a use-after-free across requests. Workers persist, and some of their global state is meant to be reset at the start of each request. If an earlier request published a pointer to its own memory and then died before the reset, the pointer outlives the memory it points to.[2] The advisory lays it out as producer, free, consumer. The Foundation’s postmortem adds that a use-after-free and worker crash were confirmed and that code execution was demonstrated against a real application on Apache mod_php:[2][28]
Fig. 5 — A dead request leaves a loaded gun on the worker
CVE-2026-109619 · producer, free, consumer
Producer and consumer must hit the same worker. Extra workers and worker recycling lower the chance per request but do not remove the condition.[2][6]
Four families of stale state
Error state
Warnings and diagnostics raised during shutdown or extension cleanup, after the error state was already cleared, can repopulate it. A diagnostic raised while per-request settings are applied can read it before initialisation.[2]
Fatal-error backtrace (PHP 8.5)
When fatal_error_backtraces is enabled, the request owns a backtrace whose reset is always skipped at shutdown. This is the confirmed code-execution case under mod_php, and the feature is on by default in 8.5.[2][6]
Session upload-progress state
Session and decoder globals are initialised during multipart parsing, before normal session setup. The feature is on by default and does not need the application to call session_start().[2][6]
Object and extension state
Described only in general terms. PHP does not name a confirmed instance but lists the family because the same lifecycle gap exists.[2]
Producers and consumers
Producers are anything that interrupts a request before its reset: parse or compile failures, uncaught errors, a failed require, an out-of-memory fatal, or “Maximum execution time exceeded”. A timeout counts as a fatal error, so any slow path an attacker can reach is a producer, and changing the timeout alone does not help.[2]
Consumers are operations that touch the stale state before startup resets it. The advisory confirms two. The first is an INI diagnostic: a warning, notice or deprecation raised while per-request settings are applied, which does not need to be displayed or logged. Deprecated settings, an invalid memory_limit, date.timezone, an open_basedir-rejected path or a malformed number all qualify.[2] That is why @, display_errors=0 and error_reporting do nothing: they hide the message, not the event.[2] The second consumer is session upload progress.[2]
Where per-request settings come from decides who is exposed. Under mod_php, .htaccess and php_value/php_flag/php_admin_* directives apply before php_request_startup() and can act as early consumers; ordinary php.ini is read at startup and not re-applied. Under FPM, pool values apply at worker start and .user.ini after normal initialisation, so neither provides the early window, but a front end that passes PHP_VALUE or PHP_ADMIN_VALUE that triggers an early diagnostic does.[2]
The bug is not in your application. That is exactly why your application cannot fix it.Omar Babba
Section 07Reconciling the Descriptions
If you read only PHP’s advisories, CVE-2026-109618 is the out-of-memory corruption and CVE-2026-109619 is the stale global state.[1][2] If you read the Wiz and Sansec material, CVE-2026-109618 is described as an upload-progress unserializer use-after-free with a memory-disclosure side effect, and CVE-2026-109619 as a fatal-error backtrace use-after-free plus an OPcache type confusion.[4][5] Imperva classifies both as CWE-824, while PHP lists several weakness classes for them.[11][1][2]
The two readings are not necessarily contradictory: the researchers describe primitives they chained, while PHP describes the root cause classes it fixed. In practice nothing depends on the mapping, because both CVEs are fixed in the same releases. Use PHP’s advisories as the authority on classification, and treat any researcher mapping of “primitive to CVE” as informative rather than definitive.
| Primitive (researchers’ term) | What goes wrong, conceptually | Reported by | Where it matters |
|---|---|---|---|
| Interrupted hash-table insert | A counter is updated before the key is allocated; teardown trusts a half-built entry. | Calif[3] | mod_php, where shutdown runs after a failed start |
| Upload-progress session state | Session globals set up during multipart parsing dangle after a fatal; a later multipart request reads them. | Calif, Wiz[3][4] | mod_php; an FPM variant needs a later fatal |
| Process-memory disclosure | A stale session-ID pointer and length are trusted by a later request, and heap bytes come back URL-encoded in a PHPSESSID cookie, with no session_start(). | Wiz, Sansec[4][5] | No code execution needed; leaks other requests’ data |
| Unserializer bookkeeping left published | Per-decode state and nesting level survive a fatal; a later request reuses them and the result can be steered into memory corruption. | Calif, Wiz[3][4] | FPM and mod_php; needs a decode path such as session or unserialize() |
| Fatal-error backtrace not cleared | A global backtrace pointer dangles after an out-of-memory fatal; an early diagnostic dereferences it. | Wiz, PHP advisory[4][2] | PHP 8.5, mod_php confirmed |
| OPcache type confusion | A process-local counter advances before the shared frontier is published; an allocation failure between the two lets another worker reuse a slot with the wrong type. | Wiz[4] | Workers sharing OPcache memory |
Names and mechanisms are as described in the researchers’ write-ups.
Section 08SAPI Matrix
| SAPI | On startup failure | CVE-2026-109618 (OOM) | CVE-2026-109619 (stale state) |
|---|---|---|---|
| Apache mod_php | Shutdown still runs | Confirmed RCEValidated over HTTP, default limits, prefork workers.[1] | Confirmed8.5 backtrace RCE; session-lifecycle RCE validated.[2] |
| PHP-FPM | Child process exits | Confirmed via app pathsThe startup-failure sequence is blocked; RCE was confirmed through application-level code paths. The advisory noted no complete exploit of the startup sequence itself.[1][28] | ConditionalSession-lifecycle RCE validated with a dynamic pool and an application-dependent fatal; front ends passing PHP_VALUE can supply an early diagnostic.[2] |
| php-cgi | Not analysed separately | Listed at riskPHP lists it among affected SAPIs; no SAPI-specific analysis in the sources reviewed.[6] | Listed at risk |
| FrankenPHP | Calls shutdown unconditionally | Likely like mod_phpSource analysis only.[1] | No early consumer in default configPHP says this is not immunity.[2] |
| LiteSpeed (LSAPI) | Modelled like FPM | UnvalidatedApplication-specific exploits likely but not shown.[1] | ConditionalCan apply environment INI values early; no equivalent consumer established by default.[2] |
Read the matrix as an ordering of urgency, not a list of safe configurations. “No exploit shown” means exactly that, and PHP’s guidance is to treat every SAPI that serves web requests as at risk.[7][6]
Section 09How This Was Found: Twenty-Two Years and a Few Weeks
Fig. 6 — A known class, left half-fixed
Milestones from 2004 to the October 2026 patches
Sources: Calif’s history section and the PHP Foundation’s postmortem;[3][28] the 2020 bug is also discussed in the community thread.[19]
The first memory-limit remote vulnerability in PHP was disclosed by Stefan Esser in 2004, who withheld his exploit; two commercial vendors reportedly built private ones and the public “exploits” that circulated were fakes.[3] In 2020 bug #78876 reported that very long variables in multipart bodies could cause out-of-memory conditions and leave temporary files uncleaned. A commenter in the community thread explains that the fix stopped a negative-length cast and did not add cleanup on allocation failure.[3][19] In 2024 PHP had its first external security audit in years, funded by the Sovereign Tech Agency, organised through OSTIF and performed by Quarkslab. While fixing an issue the audit reported, a contracted core developer found the first signs of the out-of-memory problem. An exploit was theorised but no concrete route was found, and the fixes on the table each had a cost: a backward-compatibility break, new denial-of-service potential, or changes to many third-party extensions that seemed hard to coordinate. The consensus-based security team could not choose, and the work stalled and restarted for months. The Foundation calls this a structural failure of process and resources.[28][3][33] The pattern repeats: a resource-exhaustion bug, judged low impact, left room for the next researcher.
Three reporters, one fortnight
Fig. 7 — Calif, OpenAI and Wiz converged independently
July to October 2026 · to scale · numbered by lane, matching the key below
The 71 and 58-day counts are derived from the first report date to the 21 October release.[3][4][5] Trail of Bits, which has also been auditing PHP, is reported to have found the same bugs.[32]
- 130 Jul. Calif joins OpenAI’s “Patch the Planet” initiative; the PHP Foundation is involved through Volker Dusch.[3]
- 21 Aug. First out-of-memory fatal and first interruption point found.[3]
- 311 Aug. Calif reports the first bug to PHP; OpenAI independently reports the same root cause the same day. Coordinated disclosure begins.[3][28]
- 414 Aug. Code-execution proof of concept shared with PHP.[3]
- 515 Aug. PHP confirms the proof of concept works.[3]
- 621 Aug. Calif reports a second bug.[3]
- 718 Sep. OpenAI reports further attack vectors.[28]
- 819 Aug. Wiz finds its first PHP vulnerability.[4]
- 920 Aug. Wiz confirms unauthenticated RCE against Drupal.[4]
- 1021 Aug. Wiz confirms unauthenticated RCE against WordPress.[4]
- 1124 Aug. Wiz reports further attack vectors to the PHP security team.[4][28]
- 1221 Sep. PHP acknowledges Wiz’s reports and begins a coordinated fix, per Wiz.[4]
- 1320 Oct. Details leak.[5][15][28]
- 1421 Oct. Patched releases and public disclosure.[1][2]
Calif’s researcher also publicly posted a hash of one finding on 5 August, a standard way to timestamp a discovery without revealing it.[3][57] Three independent reporters, Calif, OpenAI and Wiz, reaching the same bugs within thirteen days of each other is itself a finding: it suggests the bugs were findable by anyone who asked the right question, which raises the odds that others, including attackers, asked it too.
The role of AI
Both teams describe AI as part of the method, and their accounts are consistent. Calif says an LLM helped identify ways to reach memory_limit on demand, and an audit agent reviewed the memory manager, fatal-error reporting and request shutdown for places where an interruption could leave inconsistent state. Those findings were generalised into a reusable skill file that hunts the “publish, fallible work, skipped commit” pattern.[3] Calif stresses that human knowledge of PHP’s vulnerability history was needed to steer the model, because default variant analysis favoured newer, more prominent bugs over obscure older primitives.[3] Wiz says it used several frontier models, credits one of them with contributions to discovery, exploit development and patch validation, and claims one researcher did in a week what would previously have taken a world-class team months.[4]
The “vendor-reported” label applies: both firms sell security products and have reasons to emphasise the AI angle. Even so, the direction is plausible and the practical implication is clear. Triage decisions of the form “resource exhaustion, unlikely to be exploitable” deserve suspicion in long-lived C codebases, because AI-assisted variant analysis now makes it cheap to ask what such a bug can be combined with. Expect more findings of this shape in other runtimes.
What PHP is changing. Since 1 July the security team has published 15 CVEs and triaged more than 100 reports that were invalid, duplicates or not reproducible. It says AI helps validate and group reports but people make every decision and write every patch. It created an Ecosystem Security Team in May, is moving from consensus to majority decisions, and has asked companies, hosting providers and governments for sustained funding. The Foundation itself used AI tooling: an earlier AI-assisted scan and OpenAI’s Daybreak Red for validating reports and exploits.[28][33]
OpenAI’s account. OpenAI says Calif identified a critical flaw using GPT-5.6 Sol under its Patch the Planet initiative, with Wiz independently discovering and reporting both vulnerabilities, and that it led a coalition of maintainers, researchers and security providers for two months. It says it briefed US government bodies including the Office of the National Cyber Director and CISA, released a Codex skill that checks PHP versions, committed $1 billion in subsidised access for frontline defenders, and proposed a five-stage framework for responding to critical vulnerabilities. It also asked when, if ever, governments should patch systems they are authorised to manage, and floated internet-wide scanning that notifies owners or patches vulnerable systems.[39][48]
Section 10The Disclosure: Sixty-Six Hours Around the Release
The plan was a coordinated release on Thursday 22 October at 14:00 UTC, according to the PHP Foundation; watchTowr’s account put it an hour later.[28][8] PHP had reserved the right to release earlier if details became public or exploitation appeared.[27] Then it came apart in four steps: three failures and PHP’s response.
The identifiers leaked. At about 15:00 UTC on 20 October the two CVE identifiers appeared on forums and social media with a wrong release time and a wrong CVSS score of 10.0, and no technical details.[28] A Hacker News post was the visible source and was later deleted; the Foundation does not say who leaked the information.[15][28] watchTowr confirmed on social media that the CVEs were real.[15]
PHP moved early. At about 19:30 UTC PHP published its pre-announcement and brought the release forward from 22 October to 21 October at 14:00 UTC, because distributors were still packaging the fix.[28][27] CERT-EU published advisory 2026-018 on 21 October.[29]
A researcher’s video got out. At about 20:00 UTC Calif mistakenly published a video of its proof of concept working against several targets. It was deleted, but copies spread, and the Foundation says the video helped accelerate public proof-of-concept development.[28] Tenable describes a third party sharing it and crediting Calif; the Foundation’s account is that Calif published it.[7][28] From about 23:00 UTC, mitigation advice given to a few critical-infrastructure providers may also have leaked.[28]
A distributor released early. At 07:41 UTC on 21 October Chainguard published built container images containing the fix, more than six hours before the coordinated release.[28][31] The next subsection covers it. PHP then shipped 8.5.12, 8.4.27, 8.3.36 and 8.2.35 at about 13:30 UTC (CERT-EU and Huntress); other sources give times from 12:59 to 13:52, and the advisory timestamps cited by the encyclopedic summary say 13:34.[29][8][18][30][34] Minimal source backports for 7.4, 8.0 and 8.1 appeared around the same time.[26][34] Wiz announced at 13:32 UTC, its researcher Sagi Tzadik followed at 13:38 and Calif at 13:53, while LCFR, whom Calif names as the hacker who discovered the flaw, posted a demonstration video of an exploit running against WordPress.[56][55][54][53]
Fig. 8 — Sixty-six hours, three lanes
20 to 22 October 2026 UTC · numbers match the key below · grey markers are planned or approximate
Markers are numbered by lane, not chronologically. The hatched band marks the day of precautionary shutdowns. Marker 13 is approximate; marker 9 is “a few hours before the fixes shipped”.
- 120 Oct, ≈15:00. The CVE identifiers leak with a wrong release time and a wrong 10.0 score.[28]
- 220 Oct, ≈19:30. PHP publishes its pre-announcement and brings the release forward to 21 Oct at 14:00.[28][27]
- 320 Oct, ≈20:00. Calif mistakenly publishes a demonstration video; it is deleted but copies spread.[28]
- 421 Oct, 07:41. Chainguard publishes patched images more than six hours before the release.[28][31]
- 521 Oct, ≈13:30. PHP ships the fixes (CERT-EU and Huntress; other sources 12:59 to 13:52).[29][8][30][34]
- 622 Oct, 14:00. The original release time, never used.[28]
- 721 Oct, from 07:34. Patchstack hears from hosting partners about active exploitation incidents; its own telemetry at 13:57 shows probing only.[25]
- 821 Oct, 07:43. Cloudflare reportedly sees early attack traffic (Sansec’s account, two minutes after marker 4; the sources do not link them).[5]
- 921 Oct, before release (approximate). Hadrian says PHP2Shell is exploited in the wild at scale, mostly via session upload progress. A single-vendor claim with no counts.[14]
- 1021 Oct, around release. watchTowr says first attempts hit its sensors and none has succeeded.[14][12]
- 1121 Oct, 20:30. Huntress reports no exploitation on its partner systems.[8]
- 1221 Oct, 03:02. Cloudflare’s protections go live for all customers, including free plans.[24]
- 1321 Oct, before release (approximate). CERT-EU advisory 2026-018 and the UK NCSC alert urge preparation and isolation; CERT-EU updated its advisory after the release.[29][34]
- 1421 Oct, 17:00. The Czech national government website is taken offline.[17]
- 1521 Oct (all day). Government and large sites in Germany, France, Belgium, the Netherlands and Finland go offline; Wikimedia takes services down.[17]
Chainguard’s early images: confirmed, and contested
The PHP Foundation’s postmortem says Chainguard broke the embargo by publishing patched images more than six hours early while other distributors were still preparing. It calls the release unilateral, says it disregarded weeks of coordinated work, and says attackers could study the fix in binary form before most users could patch.[28][31] Chainguard’s chief executive has said he made the call because exploits were hitting in the wild, that the company had independently found the bug and notified the coordination group right after deciding, and later apologised for the stress on maintainers.[31][32] He told The Register that Chainguard heard from one of the researchers on the Friday that something was coming in PHP and that evening found the same flaws with its own AI tooling.[43] ELLIO, a threat-intelligence firm, reports the first PHP2Shell request at its sensors at 08:36 UTC on 21 October, less than an hour after the images appeared; the sources do not say whether the two are linked.[38] He cited exploitation reports from other vendors on the Tuesday night; no vendor or evidence was named.[31] Chainguard’s published policy allows shortening timelines for active exploitation, and the Foundation answers that the policy’s criteria do not show PHP authorised publication.[31] The two sides agree on the facts, the images and the time, and disagree on whether it was justified. The general lesson holds either way: when many distributors, hosts and vendors hold a patch in advance, the embargo’s weakest link is the number of people who hold it.[28]
Section 11Exploitation: What Is Evidence and What Is Claim
| Statement | Source | What it shows |
|---|---|---|
| Researchers built working unauthenticated chains against stock CMS images and other apps | Calif, Wiz[3][4] | Published by the discoverers with product versions. |
| A demonstrated mod_php exploit lets one unauthenticated request trigger the attack before application code runs | PHP’s advisory[26][6] | PHP’s own validation. |
| An exploitation attempt hit Amazon’s honeypots on 17 October, four days before disclosure, from an anonymised address; more followed on 21 October from about 02:00 UTC, with varied payloads suggesting several actors | Amazon Threat Intelligence[38] | First-hand telemetry. Amazon says it is unclear how the actor learned of the flaw during the embargo, and whether any attempt would have succeeded. |
| PHP2Shell is now being broadly exploited in the wild | CJ Moses, Amazon[38] | Amazon’s assessment; no count of successful compromises. |
| Attempts across Cloudflare’s network rose from thousands in the ten hours before the announcement to tens of thousands within 45 minutes, hundreds of thousands within two hours and millions by the next morning; attackers mutated payloads to evade its rules | Matthew Prince, Cloudflare[49][24] | First-hand network telemetry; attempts, not confirmed compromises. |
| Hosting partners reported active exploitation incidents from 07:34 UTC; the vendor’s own telemetry at 13:57 UTC showed probing only | Patchstack[25] | First-hand but unquantified, and the two statements point different ways. |
| The first PHP2Shell request reached ELLIO’s sensors at 08:36 UTC on 21 October; scanners using the user-agent php2shell-scan/109618 hit VulnCheck’s honeypots; Pantheon blocked more than 60,000 suspicious requests | ELLIO, VulnCheck, Pantheon via The Hacker News[38] | Scanning and probing at scale; no compromise reported. |
| First attempts hit honeypots, none successful so far | watchTowr via SecurityWeek[14] | Attempts only; the vendor expected success soon. |
| Attack attempts using a public proof of concept | Vega via SecurityWeek[14] | Single vendor; attempts, not outcomes. |
| No exploitation observed on partner systems at 20:30 UTC | Huntress[8] | Absence in one customer base is weak evidence either way. |
| No pre-disclosure traffic matching monitored exploit patterns | Imperva[11] | Covers only the monitoring window before disclosure. |
| CISA had not observed exploitation when it published its alert | CISA[37] | Official wording; the alert does not mention the Known Exploited Vulnerabilities catalogue. |
| Proofs of concept are circulating, which raises the likelihood of exploitation; active exploitation is not confirmed | CERT-EU advisory[29] | Primary advisory wording. |
| PHP’s team found no functional public exploits at release, and Tenable has not verified any public proof of concept | PHP Foundation, Tenable[28][7] | A sceptical position that sits awkwardly beside the researchers’ chains; the Foundation says it does not rule out exploitation elsewhere. |
| Exploitation leaves almost no trace: workers stay stable, responses return HTTP 200, application logs show nothing, and the only artefact may be one memory-limit fatal in the web server’s error log | CrowdStrike via The Hacker News[38] | Vendor assessment; it explains why compromise is hard to confirm. |
| Several other vendors reported exploits in the wild by Tuesday night | Chainguard’s chief executive[31] | Offered as the reason for releasing early; no vendor or evidence was named. |
| Exploit attempts use multipart bodies whose boundary strings reference the CVEs | One live blog[34] | A secondary compilation; a hunting hint rather than evidence. |
| Webshells, cryptominers, ransomware or APT use | Unnamed reports via Techzine[16] | No named source, victim or sample. |
Public proof-of-concept repositories. Tenable warns that code claiming to exploit these bugs is circulating, has not been verified to work, and that unverified exploit code is sometimes laced with malware. No public repository is linked here.[7]
Huntress’s FastCGI one-liner. A PHP FastCGI process was seen writing a small PHP file to the first writable temp directory, running it and deleting it. Huntress says this is unrelated to PHP2Shell and predates the disclosure.[8] Do not let it contaminate your hunting baselines.
What the evidence shows
By 22 October the public record had moved beyond research exploits. Amazon reports an attempt dating to 17 October and broad exploitation since, Cloudflare counts millions of attempts, and scanners with a distinctive user-agent were hitting honeypots.[38][49] What the record does not yet contain is a named victim or a confirmed successful compromise, and CrowdStrike’s point that exploitation leaves almost no trace means the absence of reports is weak comfort.[38] The three earlier engine-level PHP code-execution flaws, CVE-2012-1823 and CVE-2024-4577 in PHP-CGI and CVE-2019-11043 in PHP-FPM, are all in the CISA Known Exploited Vulnerabilities catalogue, and two have known ransomware use.[7] If PHP2Shell follows that trajectory, exploitation becomes routine once a reliable public tool exists.
Section 12Impact
Technical impact
Code execution as the web worker. That is typically the web server or PHP-FPM account rather than root, but it is enough to read application secrets, database credentials and uploaded data, plant a webshell, and pivot.[11][8] Rapid7’s vector rates confidentiality, integrity and availability impact all high.[6]
Memory disclosure without code execution. Wiz and Sansec describe a path where heap contents come back in a PHPSESSID cookie, even if the application never starts a session. Sansec compares it to Heartbleed and lists passwords, session tokens, API keys and TLS private keys as possible contents.[4][5] Treat the TLS claim cautiously: what can leak depends on what shares the worker’s heap, and the sources do not quantify it. The practical point is that a successful probe may leave no webshell and no file change, only a request that looked odd.[5]
Availability as a side effect. The very mitigation PHP recommends for CVE-2026-109618, removing the memory ceiling, lets a single request consume the machine’s memory, so the interim fix creates its own denial-of-service risk. Sansec says to monitor memory and restore the limit after patching.[5][9]
Operational impact: the day the web went dark
On 21 October a number of organisations chose to switch services off instead of running exposed. The Reuters factbox, which describes itself as partial, lists the first group below, almost all of them official statements relayed by Reuters;[17] the last rows come from other reports.
| Organisation or group | Country | Reason as stated | Caveat |
|---|---|---|---|
| Several federal sites run by the IT service provider ITZBund | Germany | Purely preventive, per the digital ministry | No incident known |
| Prefecture websites, per the Interior Ministry | France | Precaution while awaiting a patch | Temporary |
| Foreign ministry websites | Belgium | Reports of attacks exploiting the flaws | Belgium’s cybersecurity centre said it recorded no attacks, which conflicts with the stated reason |
| Port of Rotterdam, Overheid.nl, the KNVB, the five largest parties’ websites, “numerous” hospital sites | Netherlands | Preventive, following the national cyber security centre | List is partial; hospital count not quantified |
| Government public web services (state IT centre Valtori) | Finland | Precautionary measure | Valtori found no exploitation attempt and said it was not a breach |
| National government website | Czech Republic | Taken offline at 19:00 local on 21 Oct so patches could be applied | Restoration planned after patching |
| Foundation-supported and volunteer-run systems using PHP | Wikimedia Foundation | Precaution until safely patched | Which systems went offline was not specified |
| Local governments, two ministries, regional banks, a securities firm, universities, hosting providers, games and e-commerce sites; a tally cited in a Japanese blog counts 211 organisations by the morning of 22 October | Japan | Following the prime minister’s and the national cyber office’s calls to patch or suspend sites[44] | The tally comes from a personal blog; no Japanese organisation had announced a compromise by noon on 22 October[42] |
| Some Government of Canada websites | Canada | Precaution on the Canadian Centre for Cyber Security’s guidance, to be restored once patched[51] | Sites not named |
| Office for Budget Responsibility website | United Kingdom | Taken offline in the days before a Budget; a minister said there was no indication of a breach of Budget security[41] | The OBR gave no explanation in the report |
| Nationwide alert; no specific sites named | South Korea | Science ministry urged PHP site operators to patch at once; KISA issued an advisory[40] | AhnLab estimates about 110,000 vulnerable Korean hosts |
Other reports add Dutch news and security sites, the Dutch House of Representatives and the national cyber security centre itself. Patchstack lists the Dutch DigiD and MijnOverheid services and several Japanese services, and a live blog says two underground forums went offline and large Japanese platforms entered emergency maintenance.[5][25][34] US agencies are reported to have advised taking systems offline if they could not be updated, and Newsweek reported no evidence that US federal sites were compromised or taken offline.[20][21] Guidance from the NSA, the UK NCSC, CISA and CERT-EU converged on the same advice: patch immediately, and isolate or take offline what cannot be patched, with CISA adding that anything on PHP 8.1 or earlier should come down until fixed.[13][15][20][21][22][29][37][45][46]
Business impact
For most organisations the cost will not come from a breach but from the response: emergency change windows, outages by choice, unplanned platform migrations for end-of-life stacks and supplier chasing. Governments taking services offline pre-emptively over a runtime vulnerability is unusual. E-commerce and hosted-service operators carry the sharpest tail risk, because the same engine fault gives an attacker the web tier, the payment pages and, on shared hosting, possibly neighbouring tenants.[16][8]
Section 13The Announcements and the Public Reaction
The researchers announced within about twenty minutes of the release: Wiz at 13:32 UTC, its researcher Sagi Tzadik at 13:38 and Calif at 13:53.[56][55][54] The screenshots below were captured on 22 October; counts are as shown then, and times are UTC.
The announcements

His announcement: a screen recording of an unauthenticated exploit against WordPress 7.1.3, posted as a quote of Calif’s write-up. Calif’s own account describes him as the hacker who discovered php2shell, and PHP’s advisories credit a matching handle, lcfr-hax.[53]

Calif’s announcement, “php2shell: a tale of two PHP remote vulnerabilities”, linking to its write-up and carrying the comic-style artwork that illustrates it.[54]

Opened a thread with “Today we disclose PHP2Shell”: pre-authentication code execution shown against WordPress, Drupal and Joomla, plus remote memory disclosure from any PHP application, with a screenshot of the exploit tool in action.[55]

The company’s own announcement, calling PHP2Shell a decade-old core vulnerability reaching CVSS 9.2 and affecting 70% of the internet.[56]

A post containing nothing but a hash. Calif’s account says a researcher published a hash of one finding on 5 August, a way to timestamp a discovery without revealing it; the post gathered more than half a million views.[57]
The patch then landed in the middle of a working day in Europe and the middle of the night in Japan, and the official response was unusually public. Japan’s prime minister posted a call to act that drew more than 75 million views, against about 10 million for the NSA’s warning and just under one million for the UK National Cyber Security Centre’s.[44][45][46]
Governments and officials

Asked operators to act that night: check whether public sites use PHP, be ready to apply the patch due at 23:00 Japan time, and consider temporarily suspending a website if patching was not possible. The post was written in Japanese and is shown here in X’s automatic English translation; it also pointed to the national cyber office’s account.[44]

Said the cabinet was closely following the PHP vulnerabilities and repeated the national cyber security centre’s advice to install the patch at once and keep vulnerable systems offline until then; DigiD and MijnOverheid would return as soon as that could be done safely. He quoted the Justice and Security Minister’s post relaying the same advice. The post is shown in X’s automatic English translation of the Dutch original.[58]

Said some Government of Canada websites were taken offline as a precaution on the Canadian Centre for Cyber Security’s guidance, called PHP a global issue, and promised to restore affected sites once patches were applied.[51]

Quoted the NSA’s warning, said attackers began exploiting the flaws before the fix and that many sites run versions too old to receive it, and used the incident to argue for the FRONTIER Act on powerful AI systems, her CLAIM Act on liability, and more investment in cyber defence.[47]

Advised every organisation using PHP to prepare for the update and, if an immediate update was not feasible, to take the system offline until it could be fully mitigated. It said it would follow up with more specific guidance.[45]

Encouraged UK organisations to prepare for immediate updating of systems using PHP and, where that was not feasible, to consider taking the system offline until it could be fully mitigated.[46]
Others spoke in statements and interviews. South Korea’s deputy prime minister and science minister, Bae Kyung-hoon, said an extremely urgent response was needed because exploit code was already public, and called for automated measures such as blocking vulnerable internet-facing assets and adding firewall rules.[40] Scotland Secretary Douglas Alexander told Times Radio he had no indication of a breach of Budget security after the Office for Budget Responsibility took its website down.[41] The FBI’s cyber division told operators to watch for PHP processes unexpectedly launching command shells or downloading files.[38]
Technology leaders

Wrote that OpenAI led a coalition for two months to mitigate what he called one of the most severe open-source bugs in recent memory, found with its models under Patch the Planet, and that the bug had sat in PHP for 14 years. He said the end of the disclosure “didn’t go as planned” after the leak, and argued defenders will need new approaches, possibly including authorised defenders scanning for vulnerable hosts and, in extreme cases, patching them remotely.[48]

Gave Cloudflare’s numbers: thousands of exploit attempts in the ten hours before the announcement, tens of thousands within 45 minutes after it, hundreds of thousands within two hours, and millions by the time of his post.[49]

Said Cloudflare’s rules went live at 03:02 UTC, that the early leak meant attackers were already mutating payloads against them, and that because the flaw is in the runtime, updating plugins will not fix it: “Patch PHP.”[50]
Two voices came through coverage rather than posts. Chainguard’s chief executive, Dan Lorenc, defended the early image release in interviews and on LinkedIn, and Patchstack’s chief executive, Oliver Sild, said on X that active exploitation attempts had been confirmed by Cloudflare and by several of its hosting partners.[43][25]
Screenshots of public posts are reproduced for reporting and remain the property of their authors; each links to the original.
Section 14Myths and Facts
“My web application firewall protects me.”
“I use PHP-FPM, so I am fine.”
“I turned off display_errors and set error_reporting low.”
Hiding the message is not preventing the event. The diagnostic is still raised, and raising it is what touches stale state. The same is true of @.[2]
“I set the setting with ini_set() or .user.ini.”
“A memory limit at the container or OS level will contain it.”
“Maintenance mode or a login wall will keep attackers out.”
PHP parses the request before the application decides anything, so an application’s own maintenance mode does nothing. Stopping PHP or rejecting everything except GET and HEAD does work as an emergency measure.[5]
“Only WordPress, Drupal and Joomla are affected.”
“PHP 8.5.12 is still vulnerable.”
A widely shared post claiming a successful double-free on the patched release reached 835,000 views before it was edited to say the bug concerned was unrelated.[52]
Section 15Mitigation: What Works, What Does Not
PHP’s position is explicit: updating is the only complete fix, and no configuration change makes an installation safe.[1][2][6] The matrix below shows what each interim measure addresses. “Blocks” means it removes a confirmed path; “Partial” means it reduces exposure without closing the class; “No” means it does not help or makes things worse.
| Measure | CVE-2026-109618 path | CVE-2026-109619 path | Caveat |
|---|---|---|---|
| Patch, restart all workers, verify | Blocks | Blocks | The only complete fix; verify the binary that serves requests.[9][6] |
memory_limit=-1, set at admin level | Partial | No | Removes the predictable limit but an mmap() failure can still reach the path; raises denial-of-service risk; no pool, directory or app setting may restore a finite limit.[1][6][9] |
session.upload_progress.enabled=0, admin level | No | Partial | Blocks only the confirmed session paths; ini_set() and .user.ini are too late. PHP recommends it even after patching if unused; Upwind notes it is only one confirmed path, and GMO Flatt Security reportedly said its own earlier upload-progress workaround was incomplete.[2][9][23][34] |
fatal_error_backtraces=0 (PHP 8.5) | No | Partial | Removes the confirmed code-execution producer; other state families remain.[2] |
opcache.enable=0 | No | Partial | Suggested by Imperva for the OPcache primitive; not in PHP’s own list and costs performance.[11] |
Block multipart/form-data at the web server or proxy | Partial | Partial | Every known trigger is multipart, so this removes most routes; it breaks uploads and some forms.[5][6] |
| Decoded-size, part and nesting limits at the front end | Partial | No | Must count decoded bytes, including requests without a usable Content-Length.[6] |
| Container or cgroup memory limit | Partial | No | Availability boundary only; can kill the master and all workers unless isolated per worker.[1][6] |
RLIMIT_AS / RLIMIT_DATA | Harmful | No | Forces allocation failure, the vulnerable path.[1][6] |
Hide or suppress errors (@, display_errors) | No | No | The event still occurs.[2][6] |
| WAF or CDN rules | Partial | Partial | Only traffic through that provider; stopgap, not a fix.[13][11] |
pm.max_requests=1 (FPM) | No | Partial | Breaks the producer-to-consumer link at a performance cost; optional.[2][9] |
| Static or GET-only mode (stop PHP or reject other methods) | Blocks | Blocks | The strongest interim measure; the site loses dynamic features.[5] |
| Isolate or take offline | Blocks | Blocks | What governments chose; guidance from NCSC, NSA, CISA and CERT-EU, which advises isolating internet-facing applications until a fix is applied and verified.[13][15][20][29][37] |
Reference configuration
These are the interim settings PHP and the vendors describe, written out so they can be reviewed. They reduce exposure; they do not replace the patch. Restart every worker after any change, and confirm the value through a request served by that SAPI, not through the command-line binary.[2][5][6]
; Interim only. Patching is the fix. Restart ALL workers afterwards.
session.upload_progress.enabled = 0
; PHP 8.5 only: removes the confirmed fatal-backtrace producer
fatal_error_backtraces = 0; PHP-FPM pool file
php_admin_value[session.upload_progress.enabled] = 0
; CVE-2026-109618 interim: removes the predictable limit, but raises denial-of-service risk.
; Monitor memory, and restore a finite limit AFTER the patch is verified.
php_admin_value[memory_limit] = -1
# Apache httpd with mod_php
php_admin_value session.upload_progress.enabled 0
php_admin_value memory_limit -1# nginx (http context)
map $content_type $block_multipart { default 0; "~*^multipart/form-data" 1; }
# nginx (server or location context)
if ($block_multipart) { return 403; }
# Apache httpd with mod_rewrite
RewriteEngine On
RewriteCond %{HTTP:Content-Type} ^multipart/form-data [NC]
RewriteRule ^ - [F]# Find every PHP runtime, not just the one on PATH (containers and panels need separate checks)
find / -xdev -type f \( -name 'php' -o -name 'php-cgi' -o -name 'php-fpm*' -o -name 'libphp*.so' \) 2>/dev/null
# Check each binary; distribution builds may keep an older number, so confirm with the vendor advisory
/path/to/php -v
# Show the parsed FPM configuration, including admin values per pool
php-fpm -tt 2>&1 | grep -E 'upload_progress|memory_limit'After patching
Qualys and Tenable give essentially the same verification routine. Find every installation, including parallel branches, containers, hosting-panel packages and appliance-bundled PHP. Update the right package, binary or image and compare the full package version with the vendor advisory. Restart or redeploy workers and confirm they run the patched runtime. Then, only after verification, restore a finite memory_limit, review upload restrictions and worker recycling, and test behaviour under memory pressure, because the patched runtime can stop a worker at once at its hard threshold.[9][7]
Fig. 9 — Patch, upgrade or contain
A decision tree for each PHP runtime you find
Based on guidance from PHP, Qualys, Tenable and Sansec.[1][2][9][7][5] “Contain” steps come from the mitigation matrix above.
Section 16Detection and Hunting
The first indicators were published on 21 and 22 October, and most come from honeypots rather than victims. Amazon advises starting any investigation from 17 October, the earliest sighting.[38] The harder problem is visibility: CrowdStrike says exploitation leaves almost nothing to see, with stable workers, HTTP 200 responses and clean application logs, and a single memory-limit fatal in the error log that is routinely dismissed as noise.[38] The FBI’s own post tells operators to watch for PHP processes unexpectedly launching command shells or downloading files.[38]
| Indicator | What it is | Reported by |
|---|---|---|
| 103.216.220[.]92 | Source of the 17 October attempt on Amazon’s honeypots, geolocated to Australia and tied to a commercial anonymisation network | Amazon[38] |
| 31.223.184[.]166 · 37.19.200[.]5 · 134.209.159[.]64 · 103.114.163[.]188 · 95.217.98[.]37 | Sources of attempts on 21 October from anonymised infrastructure; varied payloads suggest several actors | Amazon[38] |
| 85.11.167[.]243 · 45.198.224[.]169 | Hosts using the user-agent php2shell-scan/109618 against VulnCheck’s honeypots, targeting CVE-2026-109618 | VulnCheck[38] |
| 109.71.252[.]97 | Host that used both flaws against VulnCheck’s honeypots | VulnCheck[38] |
Single honeypot sightings are leads, not proof of compromise, and several of these addresses belong to anonymisation networks.
Fig. 10 — Five layers of signal
From the network edge down to files, accounts and secrets
Unusually large or malformed PHPSESSID values, high field counts, repeated session parameters and memory-exhaustion errors or worker crashes are the strongest PHP2Shell-specific hints.[4][11] For the second half, Huntress recommends alerting when PHP worker processes (php-fpm, php-cgi, httpd, apache2) spawn shells, interpreters or download tools, or run reconnaissance such as whoami, id and uname -a.[8] At the network layer, Zafran’s signature keys on a body carrying both PHPSESSID and PHP_SESSION_UPLOAD_PROGRESS, a live blog reports Zeek and Suricata detections from Corelight and multipart boundary strings that reference the CVEs, and CERT-EU points to an NCSC-NL repository of software that embeds PHP. Treat the last two as pointers to check, not as verified signatures.[35][34][29]
Starting points for hunting
Starting queries derived from the signals above. They are untested against real exploit traffic, so tune thresholds and expect false positives.
# 1. Memory-exhaustion fatals in PHP, web server or FPM logs since 17 Oct
grep -E "Allowed memory size of [0-9]+ bytes exhausted|Out of memory" /var/log/php*/*.log /var/log/apache2/error.log /var/log/nginx/error.log
# 2. Sources that cause bursts of HTTP 500 on POST in a combined-format access log (tune the threshold)
awk '$6=="\"POST" && $9==500 {c[$1]++} END {for (i in c) if (c[i] > 20) print c[i], i}' /var/log/nginx/access.log | sort -rntitle: PHP or web server worker spawning shell or download tool
status: experimental
description: Generic post-exploitation lineage for PHP code execution on Linux. Baseline legitimate shell-outs first.
logsource:
category: process_creation
product: linux
detection:
parent_php:
ParentImage|contains:
- php-fpm
- php-cgi
parent_web:
ParentImage|endswith:
- /httpd
- /apache2
child:
Image|endswith:
- /sh
- /bash
- /dash
- /curl
- /wget
- /nc
- /python3
- /perl
condition: (parent_php or parent_web) and child
falsepositives:
- Applications that legitimately shell out (image, PDF or mail tools)
level: highWho can already see this for you
| Vendor | What it provides | Source |
|---|---|---|
| Tenable | Web App Scanning plugins 115719 to 115722 (PHP 8.5, 8.4, 8.3, 8.2 below the fixed versions); detection plugins for PHP version and installation; asset queries for “Programming Languages contains PHP” | [7] |
| Qualys | QIDs 389102 (PHP2Shell exposure), 45110 (PHP detected), 5019895 and 5019896 (GHSA checks), plus distribution advisories; Deep Scan finds PHP binaries in custom folders | [9] |
| Rapid7 | Remote unauthenticated checks for both CVEs; a Velociraptor artifact, Generic.Applications.PHPInventory, for inventory | [6] |
| Huntress | Detection of web server processes spawning shells and common webshell activity; Sigma and YARA planned once technical details were public | [8] |
| Wiz | Threat-intel advisory, agentless and runtime detection, and a sensor response policy (version 1.0.12768) that terminates processes showing PHP2Shell-like behaviour | [4] |
| Cloudflare | Seven rules in the Free managed ruleset and seven in the paid managed ruleset, plus a default block for high-confidence signatures, live for all plans from 03:02 UTC on 21 Oct; the first managed rules to use response-side (“full transaction”) detection. Paid plans should confirm block mode; the company says attackers mutated payloads to evade them | [24][13] |
| Imperva | Managed WAF rules for known vectors, as a compensating control | [11] |
| Zafran | A Snort and Suricata rule (SID 1026109620) matching established POST bodies that contain both PHPSESSID and PHP_SESSION_UPLOAD_PROGRESS, lab-tested by the vendor; the field pairing is its suspected trigger | [35] |
| Google Cloud | Artifact Analysis notifications, the On-Demand Scanning API and Security Command Center container and Cloud Run threat detection | [10] |
Section 17Patching by Platform
| Platform | What to do | Watch out for |
|---|---|---|
| Linux distributions and LTS vendors | Install the vendor package. Advisories exist for Red Hat (RHSA-2026:87080, PHP 7.4), Gentoo (GLSA 202610-02), Fedora (FEDORA-2026-a9eba4bbc3) and Ubuntu (USN-8948-1 and -2).[9] | Backports keep older version numbers; check the advisory, not php -v.[9] |
| AlmaLinux and the Red Hat family | AlmaLinux backported the fixes to its PHP module streams, including retired 7.2, 7.3, 8.0 and 8.1 streams, and began rolling them to production at about 21:15 UTC on 21 Oct, after Red Hat had fixed only the php:7.4 stream on RHEL 8. Restart PHP-FPM, or Apache with mod_php.[30] | Verify with rpm -q php-common; php -v will not change. Control-panel and third-party PHP needs that vendor’s own update.[30] |
| Hosting control panels | cPanel: EasyApache 4 build 25.91 with fixes for ea-php74 to ea-php85. Plesk: the changelog lists the fixed PHP versions. CloudLinux: stable fixes reported for ea-php52 to ea-php85, with alt-php coverage varying. DirectAdmin: rebuild PHP through CustomBuild. The host must still install the update and restart.[36] | From a third-party tracker that says statuses change hourly; confirm with your provider.[36] |
| Community RPM repositories | Switch to distribution packages or build from source if the repository has no update.[6][13] | rpms.remirepo.net had no packages on release day.[6][8] |
| Google Cloud | App Engine standard (8.2+) and base-image-updated Cloud Run patch automatically; App Engine flexible, GKE and self-built containers need a redeploy.[10] | 7.4 and 8.1 on its managed runtimes will not be patched; move to 8.2 or newer.[10] |
| Containers in general | Rebuild and redeploy images on a patched PHP, then roll pods or tasks.[10] | Restart is part of the fix: running processes keep old code in memory.[16] |
| Shared hosting, cPanel, Plesk | Ask the provider for evidence of patching and a restart.[8] | You cannot see or change the engine. |
| Appliances and bundled Windows software | Contact the vendor; isolate from the internet or place behind a VPN or WAF until a fix ships. CERT-EU points to an NCSC-NL repository of software that embeds PHP.[8][29] | Vendor schedules rarely match an emergency. |
| PHP 7.4, 8.0, 8.1 built from source | Use the PHP security team’s minimal source backports if you can build and test them.[7][13][26] | One community commenter says the older-branch backport appears to disable session upload rather than fix the root cause; unverified.[19] |
| PHP 5.4 to 7.3 | No fix from the PHP project. Upgrade, ask a vendor with long-term support, or take offline.[7] | These branches stay exposed indefinitely. |
Section 18The GRC View: From Technical Event to Decision and Record
Control mapping (ISO/IEC 27001:2022, Annex A)
| Control | How PHP2Shell tests it | Evidence an auditor would ask for |
|---|---|---|
| A.5.9 Inventory of information and other associated assets | Do you know every PHP runtime, including containers, hosting panels and appliances? | Asset inventory with PHP version and SAPI per system |
| A.8.8 Management of technical vulnerabilities | Time from advisory to verified fix; handling of end-of-life branches | Vulnerability register entries with dates and verification |
| A.8.9 Configuration management | Admin-level ini baseline for upload progress and memory limit, tracked and reversible | Config diffs; proof the finite memory_limit was restored |
| A.8.32 Change management | An emergency change path with approval and rollback | Emergency change tickets |
| A.5.19 – A.5.22 Supplier relationships | Hosting, CMS and appliance vendors’ patch statements | Written supplier attestations |
| A.8.15 · A.8.16 Logging · Monitoring activities | Are PHP error logs, access logs and process lineage retained and searched? | Retention settings, detection rule IDs, hunt report |
| A.5.24 – A.5.27 Incident management | Decide, preserve evidence, learn | Incident record, lessons learned |
| A.5.30 ICT readiness for business continuity | The decision to go offline, and to restore | Tested playbook for taking sites offline |
| A.8.20 · A.8.22 Network security · Segregation of networks | Isolating end-of-life PHP behind a VPN or WAF | Network diagrams and rule sets |
Clocks that may start
GDPR Article 33: notify the supervisory authority within 72 hours of becoming aware of a personal data breach. A vulnerable server is not itself a breach, but a memory-disclosure probe may leave no trace, so record why you concluded there was or was not evidence of exposure.
NIS2 Article 23: for entities in scope and significant incidents, an early warning within 24 hours, an incident notification within 72 hours and a final report within one month.
Morocco: organisations in scope of Law 05-20 should check their duty to notify the national authority (DGSSI).
A register entry you can adapt
| Field | Entry |
|---|---|
| Risk | Unauthenticated remote code execution on internet-facing PHP runtimes (PHP2Shell) |
| Threat event | A remote attacker sends crafted multipart requests that interrupt PHP and leave stale state; code runs as the web worker account |
| Vulnerability | CVE-2026-109618 and CVE-2026-109619 in the PHP engine; end-of-life branches have no fix |
| Predisposing conditions | Apache mod_php; session upload progress enabled; finite memory limit; unmanaged or embedded PHP; no multipart filtering; PHP 5.4 to 8.1 |
| Likelihood | High for internet-facing, unpatched runtimes. Rationale: public technical write-ups, researcher-built chains, reported attack attempts, low skill once a tool exists. |
| Impact | High: web-tier compromise, credential and token exposure, outages if isolated |
| Treatment | Mitigate (patch, restart, verify), avoid (take unpatchable systems offline), accept only with a named owner and an expiry date |
| Key risk indicators | Share of PHP runtimes verified patched; hours from release to verified fix; number of PHP runtimes discovered that were not in inventory; internet-facing end-of-life runtimes |
| Review | After patch verification, and again after a 30-day look-back on logs from 17 October |
Two critical flaws in the PHP engine, which underlies about 70% of websites and many embedded products, are publicly documented, and fixes exist for supported versions.
We run [N] PHP runtimes, [N] face the internet, and [N] cannot be patched yet and are being isolated.
We are patching in priority order, restarting and verifying each one, accepting short planned outages rather than running exposed, and will report completion by [date].
Section 19MITRE ATT&CK Mapping
whoami, id and uname -a from web server processes.[8]Section 20Strategic Recommendations
- 01Inventory every PHP runtime, including containers, hosting-panel packages, appliances and Windows software that bundles
php.exeorphp-cgi.exe.[9][8] - 02Patch internet-facing mod_php first, then FPM and the rest. Where you cannot patch, isolate, take offline, or run read-only or GET-only.[1][5][13]
- 03Apply admin-level interim settings (upload progress off, 8.5 backtraces off) and restart all workers, knowing they are partial.[2][6]
- 04Block multipart at the edge where the application does not need uploads.[5][6]
- 05Preserve web and PHP logs before you change anything if you suspect compromise, then isolate the server.[8]
- 06Verify, do not assume: confirm the binary serving requests is patched, that workers restarted, and that no setting reinstates an old limit. Then restore a finite
memory_limitand test behaviour under memory pressure.[9] - 07Hunt back to 17 October: memory-exhaustion fatals, bursts of 500s on multipart POSTs, odd
PHPSESSIDvalues, and web workers spawning shells.[4][8][11] - 08Consider rotating high-value secrets held by internet-facing PHP workers that were unpatched during the exposure window, because a memory-disclosure probe may leave no trace.
- 09Ask suppliers in writing for patch status on hosting, CMS, panel and appliance products.[8]
- 10Retire or contain end-of-life PHP (5.4 to 7.3 now, 7.4 to 8.1 soon). Source backports are a bridge, not a destination.[7]
- 11Make PHP a first-class asset class in vulnerability management, with the SAPI and the owner recorded.
- 12Write a “leak before patch” playbook: who can authorise taking a site offline, who files notices, how fast.
- 13Reduce the attack surface: disable session upload progress if unused (PHP recommends it even after patching), apply least privilege to worker accounts, filter egress from the web tier.[2][11]
- 14Prefer immutable, rebuildable images so “patch” means “redeploy”, and keep a tested path for emergency base-image updates.
- 15Add a virtual-patching process for WAF or CDN rules, with an owner who checks the rules are blocking, not only logging.
Section 21Outlook
- Confirmed compromises and a catalogue entry. Amazon says the flaws are being broadly exploited and Cloudflare counts millions of attempts, but no successful compromise had been publicly confirmed at the time of writing. Reports said neither CVE was in CISA’s Known Exploited Vulnerabilities catalogue on 21 October; an entry would signal confirmed exploitation.
- Cheap automation against mod_php and multipart. Because the entry path is one well-defined request type, expect scanners to key on it and on the session upload-progress route.
- Follow-up releases. The change to out-of-memory handling is deep; expect regressions to surface, and expect variant hunting in the “object and extension state” family PHP lists but has not confirmed.[1][2]
- Vendor advisories from CMS, framework and hosting-panel projects. Hardening or detection releases from WordPress, Drupal, Joomla, Magento, cPanel and Plesk are likely.
- The long tail. Estates on 5.4 to 7.3 will stay exposed; the quality of third-party backports will matter.[7][19]
- Disclosure practice. PHP is moving to majority decisions and has an Ecosystem Security Team; watch whether distributors and the Foundation agree rules for early releases after the Chainguard dispute.[28][31]
- AI-assisted variant analysis of other mature C and C++ runtimes. The same method should work elsewhere.
Section 22Sources 58
Official statements and advisories7
- [1]PHP — GHSA-w8hw-w9fx-j79w: CVE-2026-109618, “RCE via OOM corruption”
- [2]PHP — GHSA-6wmf-4rv5-p3rp: CVE-2026-109619, “RCE via stale global state”
- [26]php.net — Security advisory: critical remote code execution vulnerabilities, update now (21 Oct 2026)
- [27]php.net — Upcoming critical PHP security release (20 Oct 2026 pre-announcement)
- [28]PHP Foundation — Today’s PHP security release, and how we’re strengthening PHP security
- [29]CERT-EU — Security advisory 2026-018: critical vulnerabilities in PHP
- [37]CISA — Critical vulnerabilities in PHP require immediate patching (21 Oct 2026)
Researcher write-ups3
- [3]Calif — php2shell: a tale of two PHP vulnerabilities
- [4]Wiz Research — PHP2Shell: AI uncovers critical RCE in PHP
- [5]Sansec — PHP2Shell: Critical PHP RCE (CVE-2026-109618, CVE-2026-109619)
Vendor analysis & response guidance14
- [6]Rapid7 — CVE-2026-109618 and CVE-2026-109619: unauthenticated RCE in PHP
- [7]Tenable — php2shell: frequently asked questions about critical PHP RCE
- [8]Huntress — Rapid response: php2shell, leaked critical PHP vulnerabilities
- [9]Qualys — PHP announces critical security release for two vulnerabilities
- [10]Google Cloud — Responding to core PHP vulnerabilities CVE-2026-109618 and CVE-2026-109619
- [11]Imperva — PHP2Shell: when PHP runs out of memory at the wrong moment
- [12]watchTowr — PHP remote code execution FAQ: CVE-2026-109618
- [23]Upwind — Initial assessment: PHP2Shell, two critical unpatched PHP RCEs
- [24]Cloudflare — Cloudflare deploys protections against the php2shell vulnerability
- [25]Patchstack — Major security alert: PHP vulnerable to critical RCE, attacks ongoing
- [30]AlmaLinux — php2shell: patched PHP packages released
- [34]Precursor Security — Live blog: PHP2Shell critical PHP RCE vulnerabilities
- [35]Zafran — PHP2Shell: everything you need to know about the two critical PHP vulnerabilities
- [39]OpenAI — Patch the Planet: global response coordination as agents uncover critical vulnerabilities
Press & official-response coverage19
- [13]Help Net Security — PHP2Shell: critical PHP vulnerabilities patched, update now
- [14]SecurityWeek — PHP2Shell patches land as first exploitation attempts hit sensors
- [15]Infosecurity Magazine — Critical PHP vulnerabilities leaked ahead of scheduled security patch
- [16]Techzine — PHP shuts the internet: why PHP2Shell affects every company
- [17]Reuters factbox (via Global Banking & Finance) — websites taken offline over PHP risks
- [18]Wikipedia — PHP2Shell
- [19]Hacker News — discussion thread “PHP2Shell: AI uncovers critical RCE in PHP”
- [20]Computer Weekly — What to do as critical PHP flaws put millions of websites at risk
- [21]Newsweek — PHP vulnerability: list of websites powered by PHP as hacker threat prompts scramble
- [22]The National — PHP vulnerability: websites go offline amid critical security update
- [31]Socket — PHP Foundation says Chainguard broke security embargo ahead of emergency patches
- [32]The Record — PHP says AI review of critical bugs first sparked alarm in August, but signs surfaced in 2024
- [33]The Next Web — PHP knew about one of the flaws in 2024 but could not agree a fix
- [36]php2shell.uk — PHP2Shell on shared and managed hosting
- [38]The Hacker News — Someone tried to exploit PHP2Shell 4 days before the vulnerabilities were publicly disclosed
- [40]The Korea Times — PHP security flaws alarm Korean government, companies
- [41]PA Media (Beccles & Bungay Journal) — No breach of Budget security after critical flaw found in PHP, minister says
- [42]zephel01 — What Japan has shut down and how it is recovering from the PHP vulnerability, as of noon on 22 October
- [43]Techzine — PHP accuses Chainguard in PHP2Shell
Posts on X15
- [44]Sanae Takaichi (@takaichi_sanae), Prime Minister of Japan — 21 Oct 2026
- [45]NSA Cyber (@NSACyber) — 21 Oct 2026
- [46]NCSC UK (@NCSC) — 21 Oct 2026
- [47]Lori Trahan (@RepLoriTrahan), US Representative — 21 Oct 2026
- [48]Greg Brockman (@gdb), OpenAI — “Towards securing the internet”, 21 Oct 2026
- [49]Matthew Prince (@eastdakota), Cloudflare — 22 Oct 2026
- [50]Dane Knecht (@dok2001), Cloudflare — 21 Oct 2026
- [51]Evan Solomon (@EvanLSolomon), Canada — 21 Oct 2026
- [52]Felipe Daragon (@FelipeDaragon) — post claiming the patched release was still vulnerable, later corrected
- [53]LCFR (@lcfr_hax) — announcement post with a WordPress exploit demonstration, 21 Oct 2026
- [54]Calif (@calif_io) — “php2shell: a tale of two PHP remote vulnerabilities”, 21 Oct 2026
- [55]sagitz (@sagitz_), Wiz — “Today we disclose PHP2Shell”, 21 Oct 2026
- [56]Wiz (@wiz_io) — announcement of PHP2Shell, 21 Oct 2026
- [57]LCFR (@lcfr_hax) — hash post, 5 Aug 2026
- [58]Rob Jetten (@MinPres), Prime Minister of the Netherlands — 21 Oct 2026