A Decade-Old Memory Bug in PHP 5.4 Was Unpatchable Until Frontier Models Made It Exploitable
CVE-2026-109618 and CVE-2026-109619 score 9.2 and hit every PHP version back to 5.4. The PHP team couldn't agree on a fix for months. Frontier models closed a decade of gap in days.
The PHP project released 8.5.12, 8.4.27, 8.3.36, and 8.2.35 on October 21, 2026. Two critical vulnerabilities were fixed. Both score CVSS v4.0 9.2. Both allow an unauthenticated attacker to execute code on the server. Every PHP version going back to 5.4 is affected by at least one of them — which is to say, PHP powers roughly 70% of the web, and the fix touches the memory manager and the error handler, code that nearly every single request touches.
This is the part that should stop you: your application code is irrelevant here. No plugin bug, no misconfiguration, no outdated framework. The flaw is in the interpreter. A “Hello World” on an affected version is a remote shell if the attacker can reach a multipart endpoint.
The two bugs, in the only terms that matter
Both are memory-safety issues with the same shape: PHP mishandles a fatal error during request setup, leaves partially-initialized internal state published globally, and a later request handled by the same worker consumes that stale state as if it were valid bookkeeping.
CVE-2026-109618 — RCE via OOM corruption. If a request hits memory_limit at exactly the wrong moment, out-of-memory handling unwinds through a longjmp and interrupts request setup while internal data is only partially initialized. Subsequent cleanup treats the invalid state as valid. On Apache with mod_php, this fires before any application code runs at all. PHP’s own advisory says full remote code execution was demonstrated with default settings.
CVE-2026-109619 — RCE via stale global state. A fatal error at the wrong point leaves internal state pointing at memory belonging to a previous request. The next request on that worker uses freed memory. A use-after-free and worker crash were confirmed; the reporter demonstrated RCE against a real-world application on mod_php.
Wiz’s specific primitive for the first one is sharper than the CVE description: PHP’s session module can decode session data during upload-progress handling in the same pre-initialization window, storing request-owned bookkeeping in BG(unserialize). A fatal allocation failure destroys the request heap and leaves that global state published. On a later request, PHP consumes attacker-reclaimed memory as live unserializer bookkeeping. They combined it with a separate memory-disclosure bug to remove address uncertainty, which is what turned a memory leak into an RCE.
They packaged it as a single script — php2shell — and demonstrated unauthenticated code execution against wordpress:latest, drupal:latest, and joomla:latest. Those CMSs are demonstrations, not requirements.
The bug was not unknown. It was unfindable
This is the part that actually matters, and it’s the part most coverage gets wrong.
The OOM problem had visible signs for years. During the 2024 external security audit — PHP’s first in years, funded by the Sovereign Tech Agency, run through OSTIF, carried out by Quarkslab — a PHP core developer contracted by the Foundation found the first signs of it. By 2024 a potential exploit had been theorized. No concrete vectors were found. Other issues with clearer impact drew the attention. Then the work stalled.
The Foundation’s own account is unusually blunt about why:
The PHP security team developed several competing approaches, but each came with its own trade-offs: backward compatibility breaks, new denial-of-service potential, or requiring changes to many third-party extensions which seemed impossible to coordinate. The PHP security team, operating on consensus, struggled to choose between these and feared the repercussions of shipping the wrong choice. […] The delay was a structural failure, caused by both the security team’s decision process and its lack of resources.
Read that again. The people who best understood the bug could not agree on how to fix it, because every correct answer broke something, and the extensions ecosystem made the safe options look impossible to coordinate. The fix wasn’t blocked by ignorance. It was blocked by governance.
And then it was unblocked by a capability change, not a process change.
The AI part, stated precisely
Wiz used Wiz Atlas, Gemini 4 Argon, and GPT-5.6 Sol across the research. They say the models were used for vulnerability discovery, exploit development, attack detection, and patch validation.
The useful detail is what the models were actually good for. Memory-corruption exploits fail in ways that are specific to each target: a different PHP version, a different build, a different allocator layout, a different set of loaded extensions, and every assumption the exploit chain depends on breaks. Pre-AI, adapting an exploit per deployment meant specialist hours of manual debugging per target, which is precisely why nobody does it at scale.
LLMs can help adapt an exploit to different PHP versions, configurations and memory layouts. With testing and debugging tools, models can analyze failures and iterate on adjustments, reducing the specialist effort required for each target. This significantly lowers the barrier to scaling attacks across different deployments.
Wiz’s conclusion is the part worth sitting with: “As the time and expertise required for this work decrease, complexity may no longer provide a meaningful barrier, changing how we define what is vulnerable in practice.”
For twelve years, “is this exploitable?” was answered by “how much specialist time would this take?” That was a real barrier. It isn’t one anymore, and it wasn’t one for the defenders either — which is why this got found, disclosed, patched, and mitigated at the CDN and cloud layer inside roughly a day. Google Cloud, Cloudflare, Fastly, AWS, Akamai, Imperva, Microsoft, Vercel and Automattic all shipped out-of-box mitigations for customers who couldn’t patch immediately. That coordination is the part worth copying.
The uncomfortable symmetry
The same toolset that found this in days is the toolset that adapts an exploit per target in hours. There is no technical distinction between those two activities. The difference is entirely institutional: one team had a disclosure pathway and a coordinated patch window, the other has a $4 per 1,000 requests exploit adaptation budget.
Wiz explicitly frames this against Heartbleed and Log4Shell, calling PHP2Shell a potential third turning point — not because the bugs are unprecedented, but because the cost of turning a latent flaw into a working exploit just changed category. Every unpatched memory-safety bug in every C codebase is now a smaller gap between “theoretical” and “Monday morning.”
What to do
Patch to 8.5.12, 8.4.27, 8.3.36, or 8.2.35. If you can’t patch immediately, the vendors shipped WAF rules and detection logic — Cloudflare and Fastly both published theirs within the disclosure window, and those are worth enabling today rather than after your next maintenance window.
Until you’re patched, the signals Wiz recommends are unremarkable, which is exactly why they’re useful: unusual multipart requests followed by memory-limit errors or repeated HTTP 500s, unexpectedly large or malformed PHPSESSID response cookies, and unexplained PHP worker churn. Because these flaws execute below the application layer, your application logs may contain almost no context. Absence of log evidence is not absence of exploitation.
Then go look at your inventory with the question this actually raises: how many of your services are running an interpreter or runtime that you’d call “stable” and therefore unpatched? PHP shipped a coordinated emergency release here. The next language runtime may not.
The technical details are at Wiz, the upstream advisories are GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp, and the PHP Foundation’s account of how long the fix stalled is at thephp.foundation.