OpenAI's Models Surfaced Two Unauthenticated RCEs in PHP. The Fix Took a Day.
PHP 8.5.12 (22 Oct 2026) fixes GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp — two unauthenticated remote code execution flaws in the language runtime, commonly called PHP2Shell. Both trigger before application code runs.
Two vulnerabilities fixed in PHP 8.5.12 on 22 October 2026 are unauthenticated remote code execution flaws. Vendor advisories are circulating under the name PHP2Shell. Both are exploitable before any application code runs.
Start with the identifiers, because the changelog's shorthand undersells them badly. The 8.5.12 entry lists GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp under a summary reading "Avoid state corruption via bailout." That phrasing reads like a robustness fix. It is not. Open the advisories and the titles are unambiguous: "RCE via OOM corruption" and "RCE via stale global state." Arbitrary code execution, no authentication required.
If you are running PHP and are still choosing a patching window, this stops being a scheduling decision.
Key Takeaways: What Matters Most?
- The two PHP advisories fixed in 8.5.12 are unauthenticated remote code execution, not the milder 'state corruption' the changelog shorthand implies. Upstream titles them 'RCE via OOM corruption' and 'RCE via stale global state'.
- Neither requires a login, and both are reachable before any application code executes — GHSA-w8hw-w9fx-j79w triggers entirely within request startup, and GHSA-6wmf-4rv5-p3rp is a cross-request use-after-free requiring a producer in one request and a consumer in a later one on the same worker.
- The first is reachable through multipart parsing: a request without a usable declared content length can exceed post_max_size while still supplying decoded body data, and unrestricted part headers can exhaust memory_limit from inside a request that appears to be within limits.
- PHP 8.5.12 shipped on 22 October 2026. Reports describe a turnaround from disclosure to patched release of roughly a day, across a language underlying a large share of the web.
- This is a runtime issue, so exposure scales with how much PHP an organization runs, not with how many first-party applications it operates. There is no partial mitigation short of upgrading or taking the system offline.
Two genuinely different bugs
The interesting part is that these are not variants of each other. They reach remote code execution by unrelated mechanisms, which is why both had to ship in the same release.
The first is a memory-corruption path reachable through multipart parsing. PHP uses longjmp() to bail out of out-of-memory conditions. In some contexts, request memory is briefly reachable before it is fully initialized. If an allocation fails at that point, PHP does not account for the early exit and leaves request memory in an invalid state — and the shutdown procedure that runs afterward will read or branch on it. Upstream is direct about the reachability: several multipart problems let a request exhaust memory while appearing to stay within its limits. A request without a usable declared content length passes the initial post_max_size check and keeps supplying decoded body data. A single part can carry an unbounded number of headers, which consume substantially more memory to represent than they take on the wire.
On Apache with mod_php, shutdown is invoked unconditionally even when request startup has failed — so this can complete entirely before a single line of application code runs.
The second is a cross-request use-after-free. PHP retains global state in a worker: error state, session state, object state, extension state. That state points at memory owned by one request and must be reset before the memory is released. Certain input, configuration, session, and error-handling operations run before normal initialization of the next request, and will access stale state left behind by the previous one.
Exploitation needs a producer and a consumer: one request stores request-owned state somewhere globally reachable, and a later request on the same worker reads, frees, or branches on it before initialization resets it. A strategically crafted heap layout turns that into full code execution.
That second design has an uncomfortable property. State can survive more than one way — a fatal error can abandon an operation before its matching reset, and even a non-fatal warning can repopulate error state after it was cleared. The demonstrated producer and consumer occur in different HTTP requests handled by the same worker.
The turnaround is the actual story
A roughly one-day interval from disclosure to patched release, for unauthenticated RCE in a language underlying a large share of the web, is fast on any timeline and fast for PHP specifically, where co-ordinated multi-branch releases are the norm.
That interval is the part worth generalizing. Years of security commentary treated slow discovery as the bottleneck; fuzzing, static analysis, and bounty programs were all aimed at the find step. Finding got cheap. Patching did not — and patching is the step this week demonstrated is capable of keeping pace.
The economic reading is that the maintainer side of the ecosystem absorbed an AI-accelerated discovery load without a corresponding acceleration in coordination. The result was a good outcome. It arrived fast enough to be good only because it was fast at all.
Exposure is a property of your runtime, not your codebase
These are runtime issues. Exposure tracks how much PHP an organization operates, not how many first-party applications it wrote — the vulnerable code is the interpreter.
Which means the mitigation is neither partial nor selective. There is no feature flag, no configuration toggle, no per-application blast radius to reason about. You upgrade the runtime or you take the system offline. For anyone on an unsupported PHP version, the vendor fix is the only path, and for many that means moving.
If your stack is not PHP, none of this applies to you.
What to do
Upgrade to 8.5.12 or later and verify your runtime reports it. Do not read the release index to answer whether a fix exists — it lagged behind the changelog during this period, and an operator checking that page alone could reasonably conclude there was nothing to install. The changelog is the artifact that answers it.
If you operate mod_php on Apache, understand that the first advisory's reachable path completes before application code begins. Do not assume application-level filtering sits in front of it.
If you run an unsupported branch, treat this as the forcing event to migrate.
The Bottom Line
PHP 8.5.12 fixes two unauthenticated remote code execution flaws — GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp — both reachable before application code executes, shipped roughly a day after disclosure.
The number to remember is not the CVE count. It is that industry spent a decade automating vulnerability discovery while leaving distribution on human tempo, and this week the two were briefly close enough to measure the gap.
Get the next briefing
Signal first. Three signals, why they matter, and one action.
One concise briefing with three signals, why they matter, and one action to take.
New posts daily, briefing weekday mornings. We use your email only to send the briefing. Unsubscribe anytime. Privacy policy.
Share this article