We have written twice this week about how the PHP2Shell disclosure went and not once about why the flaws were there. The PHP Foundation's post-mortem answers that, in two different registers.

What the two flaws actually are

The two are cousins. CVE-2026-109618 fires when PHP runs out of memory and CVE-2026-109619 fires when PHP hits a fatal error. Both leave the engine holding internal data it should not trust, both end in remote code execution, both are scored 9.2, and the Foundation says both were demonstrated working rather than merely theorised. The difference is only which failure gets you there.

CVE-2026-109618 is remote code execution through out-of-memory corruption. If a request hits the memory limit at the wrong moment, PHP keeps internal data that was only partly initialised, and request cleanup later treats it as valid. On Apache with mod_php, an unauthenticated request can trigger that before any application code runs, and the Foundation says full RCE was demonstrated with default settings. It was also confirmed on PHP-FPM, through application-level code paths.

CVE-2026-109619 is remote code execution through stale global state. A fatal error at the wrong point can leave internal state pointing at memory belonging to a previous request. A later request on the same worker then uses memory that has been freed. A use-after-free and a worker crash were confirmed, and RCE was demonstrated against a real application.

Why they were hard to fix

The Foundation's framing is that both sit in memory management and error handling, "which nearly every request touches". A flaw in a parser can be fixed in the parser. A flaw in the path every request takes through the engine cannot be changed without risking every application and every third-party extension compiled against it, across the 4 supported branches at once.

The constraint was never finding it. It was changing it.

Why one of them waited

The harder admission comes next. In the same post of 21 October, the Foundation says the fix for the out-of-memory flaw stalled for months inside the project and calls that "a structural failure". It is an unusual thing for a project to publish about itself on the day it ships the fix.

What is changing as a result is specific rather than rhetorical. The security team is moving to majority decisions, so a single unresolved objection no longer parks a fix indefinitely. An Ecosystem Security Team was created in May. Two engineers joined in July and September. The project now has an AI Security Engineer in Residence, and after one AI system was used to scan the codebase it added a second for validating reports and exploits, alongside sanitizer builds and reproduction environments matching CI on every supported platform.

Read that list next to the week's argument about AI buying defenders time. The window lasted days. The decision process lost months. Only one of those is worth fixing first, and the Foundation is the party saying so.

The 2024 audit

PHP's core was audited in 2024 by Quarkslab, organised by OSTIF and funded by the Sovereign Tech Fund. That audit reported 2 high, 6 medium, 9 low and 10 informational findings, among them CVE-2024-8929, a heap over-read in the MySQL driver, and CVE-2024-8928, a memory issue in the PHP filter whose details were withheld while maintainers worked.

One of the finding firms has said auditors rediscovered an out-of-memory problem dating back two decades. The published audit summary does not mention it, and we have not read the full report. Treat the connection as claimed rather than established.

The release shipped a second heap corruption

This is the part that has not been widely reported, and it is verifiable in the open.

Hours after 8.4.27 and 8.5.12 went out, a developer opened php-src issue 24488: on both versions, the garbage collector double-frees the properties table of a SimpleXMLElement, producing the message "zend_mm_heap corrupted". It reproduces with a short script using a cast, a json encode, or a call to get object vars on a SimpleXMLElement inside a collected cycle. Version 8.4.26 is fine.

The reporter bisected it to a single change in gc collect white, which adds a table to the garbage buffer. SimpleXML releases that table in a way that does not remove it from the buffer, so the collector frees it a second time.

The important part: that change is not the PHP2Shell fix. It came from php-src issue 24050, an unrelated garbage collector bug reported on 1 October and fixed on the 2nd, which simply rode along in the emergency release. A maintainer marked the regression Verified, wrote "I came to the same conclusion but I m still testing it", and the fix was merged on 22 October, inside a day.

So the release that everybody was told to install immediately also carried a heap corruption, found by somebody reading the diff on the day. It was handled well. It is still worth knowing that an emergency release is not a single change.

What to do

  • Update. The two flaws are the larger risk by a distance and nothing here argues otherwise.
  • If your application uses SimpleXML and you are on 8.4.27 or 8.5.12, test it before you assume the upgrade is clean, and take the next patch when it ships.
  • Treat an emergency release as a release. It contains everything merged since the last one, not just the fix in the headline.
  • If you maintain software that depends on PHP, the Foundation's funding appeal is in the same post. Security here still rests on a small number of paid developers.

What is not established

  • Whether the 2024 audit found this specific out-of-memory problem. One participant says so; the published summary does not.
  • How long the OOM issue was actually known inside the project. The Foundation says months, and does not date the start.
  • Which objections stalled the fix, or who raised them.
  • Whether anyone has been compromised through either CVE.
  • How many installations hit the SimpleXML regression before it was fixed.
  • Whether other extensions have the same double-free pattern. The reporter raised it and maintainers had not decided.