memujo
Technology8 min read

AI Turned a Decade-Old PHP Bug Into a Web Killer

Wiz and Calif used frontier AI models to turn a decade-old PHP memory bug into unauthenticated remote code execution affecting 70 percent of websites.

By Alice

In this article
  1. 01The story behind the patch
  2. 02What actually broke, in engineering terms
  3. 03The attack curve after disclosure
  4. 04Why This Matters: the exploitation cost curve just broke
  5. 05Outlook: coordination built for the old clock

On October 21, 2026, the PHP project shipped emergency releases with a message that appears roughly once a decade: update now, everyone. The PHP security advisory names two CVEs, CVE-2026-109618 and CVE-2026-109619, both capable of unauthenticated remote code execution, and fixes them in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, with minimal source backports for the end-of-life branches 7.4, 8.0 and 8.1. The vulnerabilities sit in the core engine, not in any application, which is why the advisory treats every installation serving web requests as at risk, and calls mod_php deployments the worst case, where a single unauthenticated request can trigger the attack before any application code runs.

What makes this disclosure a landmark is not the bug class. Use-after-free errors in interpreters are old news. What makes it a landmark is how the exploits came to exist at all, and how fast attackers moved once the details went public.

The story behind the patch

Wiz Research published the full technical writeup on the same day. The team, led by Sagi Tzadik and Shir Tamari, grouped four exploitable memory-safety bugs under the two CVEs, with severity reaching CVSS 9.2. All of them trace back to the same architectural pattern: PHP handles a fatal error, typically an out-of-memory failure, while processing a request, and the request teardown leaves corrupted or stale internal state behind. A later request, or a different worker sharing state, then trusts that leftover data as live.

The consequences are severe and, crucially, application-agnostic. Wiz built a single exploit script, php2shell, and demonstrated unauthenticated remote code execution against the latest official container images of WordPress, Drupal and Joomla. A separate primitive leaks live process memory into a PHPSESSID response cookie, exposing passwords, authentication tokens, API keys and certificates belonging to other users' requests, even on an application that never calls session_start(). Wiz's summary is blunt: every PHP version released in the last decade, back to 5.4, is affected by at least one of these issues.

The AI angle comes from the discovery and exploitation process itself. Wiz ran the research through its Atlas pipeline with Gemini 4 Argon and GPT-5.6 Sol, and the security firm Calif independently found the flaw using OpenAI models through the Patch the Planet initiative. The vulnerable code had been in the PHP codebase for more than a decade, invisible to years of human review and fuzzing, because turning it into a working exploit required chaining multiple bugs and repeatedly adapting the chain to each target's memory layout. Wiz's conclusion, in their own words: with frontier models and the right tools, a single researcher completed in a week what previously would have taken a world-class team months of work.

What actually broke, in engineering terms

The four bugs are worth naming because they are not exotic. They are consequences of one design decision: a persistent worker process that serves many requests while keeping global state between them.

Bug CVE What an attacker achieves
Upload-progress unserializer use-after-free CVE-2026-109618 Pre-auth RCE on WordPress, Drupal and Joomla
Remote process-memory disclosure CVE-2026-109618 Unauthenticated leak of PHP worker memory
Fatal-error backtrace use-after-free CVE-2026-109619 Pre-auth RCE on Drupal
OPcache type confusion CVE-2026-109619 Cross-worker shared state corruption, RCE on WordPress

Walk through any of them and the same shape appears. PHP parses multipart upload requests during request startup, before modules initialize. An allocation failure aborts the request mid-state-change. The heap is destroyed, but a global pointer, say PS(id) or EG(last_fatal_error_backtrace), still references freed memory. The worker survives, and the next request follows the dangling pointer. The OPcache variant is the most insidious: the process-local map frontier advances before the shared frontier is published, so after a failed persistence, one worker's stale metadata resolves to another worker's object of a different type. That is a cross-worker type confusion in memory shared by every PHP process on the box.

The PHP team's interim guidance confirms how low-level this is. To blunt the stale-global path, you set session.upload_progress.enabled=0 in php.ini or an FPM pool config, everywhere that applies before request parsing, and restart every worker. The advisory explicitly warns that ini_set() and .user.ini are too late, and that hiding diagnostics with error_reporting or display_errors does nothing, because the vulnerable code path emits output before initialization. Only the update is a complete fix, and Wiz notes there are other tracked, and likely untracked, variants of the same pattern still in the codebase.

The attack curve after disclosure

The second dataset that matters comes from Cloudflare. CEO Matthew Prince reported the exploitation timeline, as relayed by Analytics Insight, and the numbers read like a stress test of the assumption that disclosure is safe once a patch exists:

Time relative to disclosure Exploit attempts observed by Cloudflare
10 hours before announcement Thousands
45 minutes after Tens of thousands
2 hours after Hundreds of thousands
Same day Millions

The pre-disclosure "thousands" already tell you scanners were probing for something. The post-disclosure curve is the real signal: two orders of magnitude of growth in under two hours, on the same day working exploit code became public. Real-world disruption followed immediately. Government websites in the Netherlands, France, Finland, Denmark and Canada went offline while operators patched, and in Japan, Mitsubishi UFJ Financial Group suspended some internet services while the Finance Ministry pulled website content as a precaution.

Why This Matters: the exploitation cost curve just broke

As a data scientist, the number I keep returning to is not CVSS 9.2. It is the ratio inside Wiz's own account of the work. The vulnerable code was static for more than a decade. The fuzzing history was static. The reviewer pool was static. The only variable that changed was the marginal cost of building and adapting an exploit, and frontier models moved that variable by something between an order of magnitude and two, from months of a world-class team to a week of one researcher.

That reframes what "hard to exploit" means. For ten years, PHP's error-handling paths were defensible in practice because the exploit required chaining a use-after-free with a memory disclosure, then re-tuning the chain per target, per PHP version, per configuration, per heap layout. Each retargeting was a specialist task: run it, watch it crash, diff the memory state, patch the offsets. Cost per additional target scaled linearly with scarce human hours, so attackers rationalized their effort toward the biggest victims only.

Agentic loops invert that economics. An LLM with build, debug and test tools turns each retargeting into an iteration: propose an adjustment, run the chain, read the failure, adjust again. The first target still costs expert time, but every subsequent target costs tokens. Wiz states the consequence plainly: as AI reduces the effort to adapt complex exploits, vulnerabilities that once seemed impractical to exploit become viable targets, and complexity may no longer provide a meaningful barrier. Defenses that were really bets on attacker laziness, unusual memory layouts, low-traffic platforms, odd configurations, are now bets against a pipeline that treats those as parameters, not walls.

For software engineers, the audit this triggers is narrower and more concrete than "rewrite PHP in Rust." Ask what your long-lived process keeps alive between requests, and what happens to that state when a request dies of a fatal error halfway through. PHP's globals are the headline case, but every persistent worker that caches request-scoped pointers, whether a Java servlet with thread-locals, a Go server with pooled buffers, or a Node process with module-level state, deserves the same question. Then check your testing: fuzzers that assert on crashes miss the case where the crash handler itself is the vulnerability. The bug here only bites after the fatal error fires, which means coverage of the teardown path, not just the happy path, is what would have caught it.

The defender-side flip is the reason to be cautiously optimistic rather than fatalistic. Wiz, Calif and OpenAI used the same class of models to find, exploit, verify patches for, and build detections around the flaw before criminals could, and Wiz reports adapting working exploits across multiple applications in hours. This mirrors a pattern we have followed across the ecosystem: models crossing offensive thresholds in evaluations, labs hardening cyber capabilities in response, and defenders now racing automated attackers in the open, as in the Hugging Face intrusion. PHP2Shell is the first case where the defensive race was won before disclosure on a flaw of this blast radius.

Outlook: coordination built for the old clock

OpenAI used the moment to propose a five-stage framework for critical vulnerability response: validate and fix upstream, give affected organizations time to prepare, coordinate with government partners, prepare updates across affected products, publish guidance and support deployment. It is a proposal seeking feedback, not a standard, and decision authority stays with maintainers. The timeline it codifies is worth measuring: Wiz reported the flaws to PHP on August 24, the team acknowledged on September 21, and patched releases landed October 21, 58 days end to end, with a two-month quiet window in between.

That 58-day gap is the number to watch going forward. It held only because the research stayed coordinated. Nothing in the October 21 attack curve suggests the same flaw, independently found by a criminal lab using the same tools, would have bought the internet ten weeks. The practical checklist for anyone who operates a web server did not change since the advisory went up: upgrade to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 now, treat the interim mitigations as partial, and stop assuming that a bug nobody has exploited for ten years is a bug nobody will exploit next week. The decade of quiet was not evidence of safety. It was evidence of cost. The cost just dropped, and the millions of scan attempts inside Cloudflare's first day measured exactly how much.

  • #ai
  • #cybersecurity
  • #php
  • #vulnerability
  • #openai
  • #wiz
  • #cloudflare

Sources

Share this story