Tuesday, 27 October 2026 Issue 2026.44 Est. 2008 About RSS
Engineering Journal A publication for the world
SWSoftware & AI REF SW-KGDV

PHP2Shell: How AI Helped Expose Two Critical PHP Core Flaws Dating to 2012

Two use-after-free bugs in PHP's engine, rated CVSS 9.2, survived a 2024 audit. An AI-assisted effort then turned them into working exploits, with consequences for how legacy code gets maintained.

Published
DisciplineSoftware & AI
Reading6 min read
Sources08
Language ENESFRDEIT
Rows of web servers in a data centre, the kind of infrastructure running PHP-based sites
FIG. SW-KGDV — Rows of web servers in a data centre, the kind of infrastructure running PHP-based sites Image: Feliciagrace-bytesrack / Wikimedia Commons · CC BY 4.0

On 21 October 2026, the PHP project shipped four emergency releases for two engine-level vulnerabilities that allow unauthenticated remote code execution. The fixes landed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, and both flaws, CVE-2026-109618 and CVE-2026-109619, are rated CVSS v4.0 9.2. The underlying weakness is old. According to Calif's technical write-up, the earliest affected code path dates to PHP 5.4.0. That release is from 2012, well over a decade ago. Part of what makes the case notable is how often the weakness had already been seen and set aside.

01Two bugs, one root cause

Both flaws sit in the PHP runtime, not in WordPress, Magento or any plugin. Calif reported that an unauthenticated attacker could run code on stock installs of Magento, WordPress, Drupal, Joomla, MediaWiki, Roundcube, phpMyAdmin, Nextcloud, Laravel and Symfony, among others. Sansec notes that because the flaw is in the engine, stores are affected even when their own code is clean.

The shared mechanism is how PHP handles fatal conditions. When a request exceeds its memory_limit (128 MiB by default) or hits another fatal error, the C engine cannot unwind its stack step by step. It calls zend_bailout(), a wrapper around longjmp(). A longjmp abandons whatever C code was running, with no chance to finish half-built data structures.

The hash table behind every PHP array, including $_POST, shows the problem. Calif's write-up, as relayed by Pentera, shows that the entry counter is incremented before the key is allocated, so a slot is counted as live before its key and value exist. If the key allocation crosses memory_limit, the bailout fires at exactly that point. A field with a nested name makes PHP insert the outer name as a new array key, so the attacker controls the key length. Sizing it to cross memory_limit places the bailout on the allocation. Cleanup then trusts the half-initialised entry.

The two CVEs split along the request lifecycle:

  • CVE-2026-109618: memory corruption during out-of-memory handling, triggered during request startup, before any application script runs.
  • CVE-2026-109619: request-owned internal state survives after its backing memory is freed, and a later request on the same worker may use that stale state before normal initialisation resets it. Rapid7 reports that the advisory confirms RCE against mod_php through PHP 8.5's fatal-error backtrace feature, which is on by default, and a session-lifecycle RCE against mod_php and FPM.

CISA lists the exposed surfaces as Apache with mod_php (which PHP considers highest risk), PHP-FPM, php-cgi, FrankenPHP and LiteSpeed.

02Why it stayed hidden

Forcing an out-of-memory condition is easy to describe and hard to do remotely. By default, PHP caps incoming uploads with post_max_size, which is 8 MiB. A request that small cannot normally exhaust a 128 MiB heap. Calif found ways around this. PHP checks post_max_size against the declared Content-Length but does not enforce it against the bytes it actually consumes, so Apache can pass chunked HTTP/1.1 or lengthless HTTP/2 multipart requests with no meaningful declared length. A second route exhausts memory_limit with a multipart request that stays under post_max_size.

Configuration still matters. CrowdStrike says the URL-encoded path it demonstrated needs roughly memory_limit < 4 × post_max_size, which PHP's shipped defaults do not meet. Rapid7 likewise found that public proofs of concept each work only against a specific mix of OS, PHP version and web server, and none looks broadly reliable. That is a limit on current public tooling. It does not make the bug safe to leave in place.

The history explains the decade of obscurity. Accounts agree that the memory-limit interruption idea was published by Stefan Esser in 2004. A related out-of-memory issue in multipart parsing was reported in 2020 (some accounts say 2019), and a 2024 OSTIF/Quarkslab audit flagged a related bug but left exploitation unproven. Each time, a plausible corruption lacked a demonstrated path to code execution, so it stayed a low-priority robustness bug. Turning "might corrupt memory" into "reliably yields a shell" takes sustained, specialised effort, and that effort is what changed.

03What the AI actually did

The attribution is more complicated than the headlines suggest. Calif says it found the first flaw on 1 August 2026 under OpenAI's "Patch the Planet" initiative and reported it to PHP on 11 August. A secondary analysis says Calif describes AI analysis guided by a researcher's hypothesis, while Wiz describes AI contributing across discovery, exploit development, attack detection and patch validation. The same analysis says OpenAI's Codex Security filed an independent root-cause report on 11 August and further attack vectors on 18 September. Model names (GPT-5.6 Sol, and for Wiz also Gemini 4 Argon) come from secondary reporting, not the PHP advisory.

Not everyone treats this as AI discovering something new. One critic argues that every piece of PHP2Shell was already in public training data. That reading fits the record above. It also sharpens the point. The model's contribution looks less like spotting a novel bug class and more like the patient work of tracing execution paths, chaining primitives and building a working exploit. One account describes AI agents tracing flaws in hash table initialisation order and paths where an invalid state table was referenced during POST parsing. Human audits had stopped short of that.

04Disclosure, leaks and the patch scramble

The coordinated process was disrupted. PHP announced on 20 October that the release would come on 21 October at 14:00 UTC. Bitdefender reports that Chainguard published container images containing the fix more than six hours before the release, breaking the embargo. It adds that PHP says no technical details leaked, but an exploit video sped up development of proofs of concept. Sansec researchers expected mass attacks within 15 minutes of release, according to Ars Technica. Amazon officials said attackers began "broadly" attempting to exploit the flaw, according to the Tech Xplore piece. On 26 October, CISA added both CVEs to its Known Exploited Vulnerabilities catalogue.

The patch map is uneven. AWS lists affected ranges of 8.5.0–8.5.11, 8.4.0–8.4.26, 8.3.0–8.3.35 and 8.2.0–8.2.34, with no upstream fix for PHP 5.4–8.1. Tenable adds that the PHP team supplied minimal source backports for 7.4 through 8.1, while 5.4 through 7.3 get nothing from the project. Interim settings help only partly. For CVE-2026-109618 the advisory suggests memory_limit=-1 set non-overridably, a low post_max_size, and request-size limits at the proxy. Calif warns that removing the memory cap raises the risk of the server running out of memory. PHP's position is that no configuration change fully mitigates these vulnerabilities. Fleet operators also need to restart PHP-FPM or the web server so the patched runtime is actually loaded.

05What it means for legacy code

The practical lesson is about the economics of exploitation. Michael Daniel of the Cyber Threat Alliance told AFP that the time from proof of concept to exploit kits, once months, is now measured in hours or days. He also said the historical exploitation rate of 5–6% of vulnerabilities shows no sign of rising, so the change is speed, not volume. Former NSA official Rob Joyce's phrase, quoted by Daniel, is "great cleansing forest fire of old software."

Three engineering consequences follow:

  1. "Unproven exploitability" is a weaker defence. A finding closed in 2024 for lack of a proof of concept can now be reopened cheaply. Triage that depends on attacker effort being scarce will age badly.
  2. End-of-life is a security boundary. Applications on PHP 8.1 or earlier either run backports of uncertain provenance or have no fix at all. Migration cost is now a patching cost.
  3. Defensive AI scales only if triage does. Daniel warns that much of the incoming noise is unreal or sits on software never exposed to the internet, so maintainers need better filtering as AI-generated reports multiply.

What remains unproven is the long-term balance. Daniel expects AI to be turned on software before it ships, which could mean fewer such bugs in new code. For now, a memory-safety flaw in a C runtime that survived 14 years, an audit and a prior report was found, weaponised and patched in about 11 weeks. The AI tooling that closed that gap is available to attackers as well.

Sources8
  1. PHP2Shell: A tale of two PHP remote vulnerabilities (Calif Research)calif.io
  2. Critical Vulnerabilities in PHP Require Immediate Patching (CISA)cisa.gov
  3. CVE-2026-109618 and CVE-2026-109619 (Rapid7)rapid7.com
  4. CrowdStrike: PHP2Shell technical detailscrowdstrike.com
  5. PHP web runtimes (AWS Security Bulletin)aws.amazon.com
  6. PHP2Shell technical advisory (Bitdefender)bitdefender.com
  7. PHP maintainers tell web devs to prepare for critical patches (Ars Technica)arstechnica.com
  8. AI discovery exposes decade-old PHP flaw (Tech Xplore / The Conversation)techxplore.com

[i]Compiled by the Engineering Journal editorial system from the sources listed below and reviewed against them. Report an error via the contact address.

SW

Related