
Two years to decide, ten weeks to ship
This morning the PHP project released 8.5.12, 8.4.27, 8.3.36, and 8.2.35, fixing two remote code execution vulnerabilities in the parts of PHP nearly every request touches: one that let an unauthenticated request corrupt memory before any application code ran, with full remote code execution demonstrated on a default Apache with mod_php, and one that let a later request use memory left behind by a previous one after a fatal error, with remote code execution demonstrated against a real-world application on the same setup. The announcement that came with the release spends almost none of its length on the bugs. It is about the queue, and about a decision that took two years.
The first signs of the out-of-memory bug date to 2024, when a PHP Foundation contractor fixing issues from the project’s first external audit (Quarkslab, paid for by Germany’s Sovereign Tech Agency) noticed the problem. An exploit was theorized, no concrete vector turned up, and the security team, which works by consensus, had several competing fixes on the table whose trade-offs nobody would agree to pay: compatibility breaks, new denial-of-service potential, changes rippling through third-party extensions. They “feared the repercussions of shipping the wrong choice,” and the Foundation’s own post calls the delay a structural failure, naming the detail plainly: work on a fix would “stall and restart repeatedly over months.”
Then this summer the economics of ignoring it changed. On July 30 the security firm Calif began auditing PHP under Patch the Planet, OpenAI’s joint initiative with Trail of Bits, and on August 11 its researcher reported the same root cause as an unconditional remote code execution, identified with GPT-5.6 Sol. OpenAI reported the same root cause independently the same day; Wiz, which OpenAI credits with independently finding both vulnerabilities, reported further vectors on August 24. From August 11 onward, fixing the bug was the top priority for the Foundation’s entire security team, worked “through weekends and around the clock.” Ten weeks after the unconditional report, the fix shipped across all four supported branches. The model did not make the decision easier. The report made dithering expensive: a choice consensus could not make in two years, a funded team with named people and full-time hours made in ten weeks.
The rest of the post prices the other side of the same tide. Since July 1 the PHP security team has published 15 CVEs and worked through “more than 100 reports that turned out to be invalid, duplicates, or not reproducible.” A week earlier, curl’s maintainer had measured his own queue the same way: “over 90% of all submissions” rate below HIGH, which is what pushed him to move low-severity reports to public issues. Finding is cheap now, for everyone. Fixing is cheap too: this week Farid Zakaria wrote the missing half of a Nix solution for Ruby lockfiles “within an hour,” after the seven-year-old tracking PR was closed unmerged, and OpenAI is putting a billion dollars of subsidized Daybreak access behind defenders who could not otherwise afford the finding side. Zakaria’s condition for the hour landing is worth keeping: Nix gives the agent “a reproducible test-bed with which to verify the correctness of the code they produce.”
The cheap-fix stream has a review bill, and Trail of Bits measured its own instead of arguing about it. The firm has co-authored “hundreds of security patches” through the same program, and reviewing every patch its engineers had written and maintainers merged, it confirmed 21 regressions across more than 130 PRs: 16 functional, one performance, four build or test, none breaking a security protection. The 21 came from 58 candidates in a single review run, about 36% precision. The answer announced today is a change of instrument, not a better prompt: two plugins whose rules require a live proof of concept for every claim (“if a step can’t produce a live PoC, its result is inconclusive”), a three-arm proof where the original code must fail, the patched code pass, and a complete revert fail again, strict schemas so each step verifies the previous step’s work “rather than trusting its summary,” and a THREAT_MODEL.md passed into every agent step. Against a plainly prompted agent, the plugin produced 25% fewer false-positive findings (their 95% confidence interval: 14 to 38%), and the same evidence gates left some known regressions classified as borderline, a tradeoff they state plainly. The plugins were released today and I have read the recipe, not run it, but the numbers come from their review of their own merged patches, not a demo.
The day also broke in three places the old disclosure runbook does not price. The CVE identifiers leaked Tuesday afternoon with wrong metadata attached, a claimed 10.0 against the real 9.2 and the wrong release time, though no technical details went with them. A Calif researcher then accidentally published a video of the working proof of concept, which accelerated the PoC circulation the team then monitored without finding a functional exploit by release time. And at 07:41 UTC this morning, more than six hours before the coordinated release, Chainguard ended the embargo by publishing built images containing the fix, which it had received in advance like any distributor: “Any attacker could now study the fix in binary form while every other PHP user was still waiting for the release.” OpenAI’s companion post proposes a five-stage response framework for findings like these and explicitly asks the community for feedback on disclosure windows. PHP’s week already contributes a datum to that consultation: a distributor with advance patch access ends an embargo by shipping, no leak of technical detail required. The distribution surface sets the real timeline, which is the same lesson the poisoned litellm build taught from the other side: the registry, not the source tree, is what users actually run.
The Foundation’s closer is mostly right: “Tools now find bugs faster than ever, for defenders and attackers alike… What tools cannot do is decide on the right fix for a long-standing design decision in the engine, weigh the compatibility trade-offs, and review the patch.” I would hand back the last third. Review is becoming delegable work, done against evidence gates, and Trail of Bits is publishing the recipe rather than guarding it. The decision half is exactly right, and this release proves it in an odd way: two years of knowing about the bug produced a stall, because every available fix genuinely cost somebody something; ten weeks of knowing its impact produced a four-branch release, because the reports did not resolve the trade-offs, they raised the price of ignoring them. What the tools cannot do is make the trade-offs hurt less.
For anyone running a report queue, the operational half is short. A queue is no longer evidence of anything either way: the hundred junk reports and the 9.2 came out of the same class of tool this summer. Sort by the evidence a machine can produce against a running instance, put the policy in the channel where reports enter (curl moved its severity threshold to intake; PHP built an Ecosystem Security Team for triage in May), and spend your scarcest people on the only part that never got cheap: choosing among fixes when all of them cost something.
Comments