PHP Ships Patches for Two Unauthenticated RCEs as OpenAI Coordinates Multi-Vendor Disclosure
Affecting About 70% of Websites: OpenAI Leads Global Discovery and Fix Coordination for Critical PHP Vulnerabilities
On October 21 at 14:00 UTC, PHP released four security versions at once: 8.5.12, 8.4.27, 8.3.36, and 8.2.35. The same day, OpenAI published a blog post with a restrained title but unrestrained content: it led a multi-organization coordinated vulnerability disclosure for two unauthenticated RCEs in PHP, both rated CVSS 9.2.
Figure: OpenAI's official announcement card 'Patch the Planet', the official release image for this global coordinated disclosure of the PHP vulnerabilities
What stands out more is the timing. According to the timeline Sansec compiled, six hours before the patches shipped, Cloudflare had already observed real attacks targeting these vulnerabilities. A day earlier, the details had leaked in security circles, and watchTowr confirmed that RCE was exploitable. In other words, by the time the disclosure went public, someone was already hitting real systems with it.
The 70% figure needs unpacking
ITHome's October 22 report used the headline 'Affecting about 70% of websites: PHP high-risk vulnerabilities fixed; OpenAI coordinates global discovery and fixes'. Most Chinese coverage attached the 'about 70% of websites' phrase directly to the vulnerability sentence, reading as if 70 percent of websites were hit by these two bugs. That reading is wrong.
The 70% is about PHP's own footprint. In W3Techs' October 22 statistics, among websites using known server-side languages, PHP accounts for 69.3%. Second-place JavaScript has only 8.1%, Ruby 7.1%, Java 5.4%, Scala 5.0%, ASP.NET 4.2%, Python 1.1%. What the vulnerabilities actually affect is sites running an affected PHP version; the scope stays inside the PHP ecosystem.
Those two facts should not be merged. One is ecosystem size, the other is this specific set of bugs. Mixed together, the number inflates into a nonexistent panic; the same conflation also lets other readers think it has nothing to do with them, when anyone running PHP is very much affected.
The bugs themselves: two use-after-free flaws, not in your code
Several online analyses have described these as 'a URL parser flaw that can lead to SSRF or bypass domain verification'. That characterization appears nowhere in the primary sources: the OpenAI post, the php.net advisories, or Calif's technical writeup. Repeating it would be a mistake.
The official php.net advisories list two engine-level memory safety issues:
- CVE-2026-109618 (GHSA-w8hw-w9fx-j79w), officially described as 'RCE via OOM corruption': while PHP handles memory exhaustion, it can be interrupted when internal request data is only half-initialized, and the cleanup phase treats invalid data as valid and keeps using it.
- CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp), 'RCE via stale global state': request-private state survives after its own memory has been freed, so when the same worker handles the next request, it consumes that residual state before normal initialization has finished.
Both are CVSS v4.0 9.2.
Figure: The cover of Wiz Research's PHP2Shell research paper, directly labeling CVE-2026-109618 and CVE-2026-109619
php.net states the exposure plainly: every PHP installation that serves web requests is in scope, PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, and LiteSpeed all included. mod_php carries the highest risk; the official text says an exploitation path has been demonstrated and that a single unauthenticated request can trigger the attack before any application code executes.
'Before any application code executes' is the worst part of this. No matter how clean the business code is, no matter how strict the parameter filtering, there is no escaping it. The bug is in the engine; the request is compromised at the front door. Calif tested and confirmed pre-auth RCE on eleven applications: WordPress 7.1.2, Drupal 11.4.3, Joomla 6.1.4, MediaWiki 1.46.2, Roundcube 1.7.4, Magento 2.4.9, phpMyAdmin 5.2.3, Nextcloud 35.0.1, Laravel 13.11, Symfony 8.1, WHMCS. The writeup adds a harsher line: the earliest affected code path goes back to PHP 5.4.0, released in 2012, and remains exploitable in default configurations. mod_php and PHP-FPM are both affected.
Figure: Wiz Research's PHP2Shell attack chain diagram; a crafted HTTP request can trigger RCE on WordPress, Drupal, Joomla and other PHP applications
The exploit chain: first get past two resource gates
Calif's writeup covers the technical details thoroughly and they deserve expansion. The goal of the whole chain is to get a controlled fatal; to do that, an attacker first bypasses two resource limits.
The first is post_max_size. PHP decides whether a request body exceeds the limit by comparing the client-declared Content-Length with the post_max_size configuration; it does not verify how many bytes were actually consumed. That leaves two openings. Under Apache, an HTTP/1.1 request with chunked encoding and an HTTP/2 multipart request without a declared length both bypass the comparison. With an input decompression filter configured, the compressed length and the decoded stream length also do not match.
The second is memory_limit. Keeping the total request under post_max_size, an attacker repeatedly stacks empty parts with filename="" under the RFC1867 upload protocol. Such parts carry no file data but still consume memory, and enough of them reaches the threshold.
Only after obtaining a controlled fatal does the real work begin. Calif found a combination of 2 fatal producers plus 3 interruptible points, turning the dangling memory on the exception cleanup path into a readable/writable primitive and finally achieving memory disclosure and RCE. The accompanying exploit tool, PHP2Shell, has been released.
Following this chain shows exactly where the model's participation shows up. OpenAI's account says Calif, with assistance from GPT-5.6 Sol, discovered one of the critical vulnerabilities. In the writeup, the part that best demonstrates that assistance value is the input construction in those two steps above: enumerating combination spaces like HTTP methods, compression filters, and empty parts, which is exactly the kind of exhaustive labor people dislike and models are good at spreading out.
In practice: check yourself, stop the bleeding, upgrade
This section is for ops and backend engineers; follow along. The procedure follows Sansec's PHP2Shell research report and the php.net advisories.
Step 1: confirm the version
php -v
The php -v output is the CLI binary's version. Web requests go through FPM or mod_php, and the two can differ. A single machine often has several PHP installs, so check them separately:
# the fpm one; replace with your actual version
php-fpm8.2 -v
# Debian/Ubuntu package view
dpkg -l | grep -E '^ii php'
# RHEL family
rpm -qa | grep php
The patched versions to match are 8.5.12, 8.4.27, 8.3.36, and 8.2.35. Anything below these needs action. PHP 7.4, 8.0, and 8.1 have ended regular official updates; this time a minimal source backport was also provided, so even older self-compiled versions can get the fix.
Walk a real case: an nginx + PHP-FPM 8.2 WordPress machine.
$ php-fpm8.2 -v
PHP 8.2.28 (fpm-fcgi) ...
8.2.28 is below 8.2.35, so it is vulnerable. WordPress is also on Calif's list of 11 pre-auth RCE apps, exploitable in default configuration; there is no point arguing about whether file uploads are enabled.
Step 2: upgrade and restart
Before upgrading, check whether the distro repo has a fix. Distro package versions often do not match upstream:
apt changelog php8.2-fpm | head -30
Security updates can be delayed in repos; if they are not there yet, go straight to the Step 3 stopgap config instead of waiting.
sudo apt update
sudo apt install --only-upgrade 'php8.2-*'
sudo systemctl restart php8.2-fpm
Adjust package names to your distro repo. The restart is not optional. FPM is a long-running process: if the binary is replaced but the process in memory is still running old code, not restarting means the upgrade has not happened.
Verify:
$ php-fpm8.2 -v
PHP 8.2.35 (fpm-fcgi)
For mod_php, run the equivalent sudo systemctl restart apache2.
At this point the case concludes: the machine was running an affected version and exposed to pre-auth RCE before the patch; after upgrading and restarting FPM, the exposure is gone. While you are in the logs, treat any POST from an unknown source with a multipart Content-Type as probing.
Step 3: if the upgrade cannot happen yet, stop the bleeding
Sansec offers three temporary mitigations, ordered from least to most intrusive.
Block multipart requests directly at nginx:
if ($http_content_type ~* "multipart/form-data") {
return 403;
}
The cost: all file uploads break, including WordPress admin image uploads. This only works for crossing the upgrade window.
In php.ini, disable upload progress and release the memory cap:
session.upload_progress.enabled = 0
memory_limit = -1
The memory_limit = -1 setting needs thought. Its logic is that an OOM fatal no longer appears, which removes the trigger from the exploit chain. But with no memory cap, a genuinely large request can exhaust memory, the OOM killer steps in, and it may take other services on the same machine down with it. Use this only if the machine has memory to spare.
The bluntest option is to allow only GET/HEAD at the entry point and reject all POSTs. API sites can tolerate it; content sites cannot.
Three more pitfalls. If you use rpms.remirepo.net, note that this volunteer-maintained repo had no updates on patch day; php.net's official advice is to switch to distro packages or compile yourself. With Docker, base images like php:8.2-fpm need a fresh pull and container rebuild; the image cache still holds the old version, and these are the easiest assets to miss. With many machines, do not forget the ones hidden behind a load balancer; they are often the problem.
Step 4: when the fleet is large, borrow the tool
OpenAI also shipped a PHP version checker in the form of a Codex skill. The idea is to encode the affected version ranges into the skill and let Codex check each machine's SAPI versions one by one. The entry point is in a link from the OpenAI post; the name is whatever the official page says. Inventorying several hundred machines by hand is genuinely unsustainable.
Figure: repository card of the open-source PHP version self-check tool that OpenAI released alongside the announcement
How the coordinated disclosure ran
The disclosure process itself is worth a look; its scale is rare.
Timeline (compiled by Sansec, UTC): August 1, Calif confirms multiple RCE paths. August 11, reports to PHP; coordinated disclosure begins. August 24, Wiz Research reports independently. October 20, details leak; watchTowr confirms RCE. October 21, 07:43, Cloudflare reports early attacks. 14:00, PHP releases fixed versions; Calif, Wiz, and OpenAI publish simultaneously.
Details leaked one day before the patch, and attacks were observed six hours before the patch. That ordering basically closed off any room to delay further.
Division of labor: under the Patch the Planet program, Calif used GPT-5.6 Sol to find one of the critical vulnerabilities, and Wiz independently found and reported both. PHP maintainers led verification, fixes, and release. OpenAI, Wiz, and Cloudflare supplied research, technical support, and cross-organization coordination. OpenAI calls this one of the most consequential security issues in recent years and introduces a concept, the defender window: as far as they know, frontier AI found these vulnerabilities earlier than attackers did.
The supporting effort reached government level. OpenAI lays out a five-phase framework: verify and fix the upstream vulnerability; give affected organizations time to act; coordinate with governments, reaching out to the White House Superintelligence Working Group, ONCD, CISA, and international partners; prepare updates for affected products; and after the patch, publish guidance and support deployment. The Netherlands moved fastest: Tweakers, the Dutch House of Representatives, NCSC, and Security.NL went offline preemptively on October 21.
How much did AI actually contribute
This is the part of the whole event I most want to untangle.
OpenAI's narrative is that AI stayed a step ahead of attackers. In the discoverer Calif's own writeup there is a dampening passage: 'The initial vulnerability discovery did not use a special harness, nor a model unavailable to the public. I focused on targets where I have background and know the vulnerability history well.' It then adds another cut: 'No single model can find all vulnerabilities from simple prompts. At least not yet.'
He also points to an inherent bias in how LLMs do variant analysis: they default to starting from the newest, best-known vulnerability and expand toward adjacent code; they do not proactively begin from an obscure exploit primitive from twenty years ago. Someone on Hacker News (id 50181175) used this to question whether OpenAI was over-crediting AI.
The two accounts do not actually conflict; put together they form the complete picture. Choosing targets and judging where to dig is human work. Calif's accumulation of PHP memory-vulnerability history is a continuation of a line from 2004. The model's contribution is the input construction that bypasses the two resource limits, a matter of combinatorial search and grunt work, exactly the zone models are good at. 'Frontier AI found it earlier than attackers' is not a lie; it just omits the subject. It was AI directed by a researcher carrying twenty years of domain knowledge, and that qualifier cannot be dropped.
An old debt that dragged for 22 years
Calif's writeup traces a longer line, and it carries more information than the incident itself.
In 2004, Stefan Esser found PHP's first memory_limit-related RCE. That year he chose not to disclose an exploit; CORE and Immunity both held private versions. In 2020, PHP bug #78876 reported that temporary files were not cleaned after OOM. In 2024, OSTIF and Quarkslab ran an audit and the same OOM issue surfaced again, but was not fixed because it was 'not proven exploitable'.
Then on July 30, 2026, OpenAI invited Calif to join Patch the Planet; Esser connected him with PHP Foundation maintainer Volker Dusch, and results were produced by August 1. A problem that auditors had seen and judged non-threatening sat for two years and was finally closed by a newly assembled collaboration chain.
The Patch the Planet main post has more numbers: Trail of Bits used Codex plus GPT-5.5-Cyber across 19 open-source projects and found hundreds of issues, including 8 kernel pointer leak PoCs and 24 local privilege escalation exploits in the Linux kernel, plus a System V semaphore use-after-free in OpenBSD that had lain dormant for 23 years. OpenAI also pledged $1 billion in usage credits through 'Daybreak for Frontline Defenders' for organizations that run critical services with limited security resources.
Questions that still have no answer
Looking back, the technology is the easy part of this incident: an old memory-safety disease, a cleanup path failure, no engine-level solution except upgrading. The real variable is process. A 22-year-old debt nobody took up, reported to PHP on August 11, fixed simultaneously in four branches worldwide on October 21, with leaks and real attacks squeezed in between.
If Wiz could independently find these two vulnerabilities, how many attackers have also independently found them? This time Cloudflare saw the traffic first and the official side got the patch out ahead of it; the window was six hours. How wide the next window is, no one can say.
Reference links
- OpenAI: official post on coordinated disclosure of two critical PHP vulnerabilities and the five-phase response framework https://openai.com/index/coordinated-disclosure-of-critical-vulnerabilities/
- php.net: official 2026 security announcements and release records for 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 https://www.php.net/archive/2026.php
- Calif: PHP2Shell exploit chain technical writeup and discovery account https://calif.io/php2shell/
- Sansec: PHP2Shell research report, coordinated disclosure timeline, and temporary mitigations https://sansec.io/research/php2shell
- ITHome: report on PHP critical vulnerability fixes and OpenAI-led coordinated disclosure https://www.ithome.com/1/016/173.htm
- W3Techs: usage statistics of server-side programming languages across websites https://w3techs.com/technologies/overview/programming_language
- OpenAI: Patch the Planet main post, including Trail of Bits and OpenBSD case data https://openai.com/index/patch-the-planet/
- Hacker News: discussion thread about this disclosure and the AI-credit dispute https://news.ycombinator.com/item?id=50181175