Safety#Security scan#AI safety#Deployment

PHP ships 8.2.35, 8.3.36, 8.4.27 and 8.5.12 to fix two unauthenticated RCEs rated CVSS 9.2 (PHP2Shell)

PHP released four fixed versions on October 21 for two unauthenticated RCEs rated CVSS v4.0 9.2, and says only upgrading is a complete fix.

Rows of black server racks in a data center aisle, with vertical strips of blue indicator lights

PHP is the scripting language that runs a large share of the server-side web, and PHP2Shell is the name the security industry settled on for two flaws in its core engine disclosed on October 21, 2026. The PHP project shipped 8.5.12, 8.4.27, 8.3.36 and 8.2.35 after 14:00 UTC that day, closing CVE-2026-109618 and CVE-2026-109619, both unauthenticated remote code execution. The CNA record, filed by PHP itself, scores both at CVSS v4.0 9.2. The release notes put the position plainly: “There are no complete mitigations, updating is the only safe choice.”

Key points

  • The four builds landed at 14:06:46 (8.5.12), 14:07:28 (8.4.27), 14:07:57 (8.3.36) and 14:09:17 UTC (8.2.35) on October 21, per the GitHub Releases API; the php.net advisory is numbered 2026-10-21-5.
  • The advisory names PHP-FPM, Apache’s mod_php, php-cgi, FrankenPHP and LiteSpeed as affected SAPIs, and calls mod_php the highest risk because an unauthenticated request can trigger the attack before any application code runs.
  • Exploitation claims conflict. TechCrunch, relaying OpenAI, reported “there were no reports of exploits in the wild”; watchTowr marked “Exploited in the wild: Yes” at 14:19 UTC on October 21; AWS says its MadPot honeypot telemetry shows an attempt on October 17.

How the bugs work

Both flaws sit in the memory management and error handling that every PHP request touches. When PHP hits an out-of-memory condition or a fatal error it calls longjmp() to abandon the current context instead of unwinding the stack frame by frame. A C function caught mid-write may already have published a pointer into global state without filling in the structure behind it. Request shutdown then treats that half-built data as valid, or the next request handled by the same worker reads a dangling pointer left by the previous one.

CVE-2026-109618 (GHSA-w8hw-w9fx-j79w) is “RCE via OOM corruption”: an out-of-memory abort interrupts PHP while internal request data is only partially initialized, and cleanup treats the invalid data as valid. CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp) is “RCE via stale global state”: request-owned internal state survives after its backing memory is freed, and a later request on the same worker can use it before normal initialization resets it.

Wiz groups four exploitable instances under the two CVE numbers: a use-after-free in the upload-progress unserializer, remote disclosure of process memory, a use-after-free in the fatal-error backtrace, and an OPcache type confusion. Wiz says the disclosure alone leaks passwords, tokens, API keys and certificates out of the PHP process, and demonstrated unauthenticated code execution against the latest official container images of WordPress, Drupal and Joomla.

Calif’s write-up explains why an ordinary site cannot dodge this. PHP compares post_max_size against the declared Content-Length before it starts parsing a POST but never enforces the same ceiling on the bytes it actually consumes, so a chunked HTTP/1.1 or lengthless HTTP/2 multipart request slips past the default 8 MiB limit. The amplification trick is just as plain: an empty RFC1867 upload part with filename="" carries no file data and does not count toward max_file_uploads, yet PHP still creates six $_FILES entries for it. Nest the field name as files[a][b][c] and each of the six entries needs its own hierarchy, so a few KB of form text can eat the default 128 MiB heap.

Disclosure and leak

The disclosure process became part of the story. The PHP Foundation’s postmortem says that around 15:00 UTC on October 20 the two CVE IDs started circulating on forums and social media with a wrong release time and a wrong CVSS score of 10.0, though no technical details leaked. PHP moved its pre-announcement forward to 19:30 UTC and pulled the release from October 22 14:00 UTC to a day earlier. The pre-announcement itself had already rated both issues CVSS v4.0 9.2.

Around 20:00 UTC the same day, Calif — one of the reporting firms — mistakenly published a video showing its proof of concept working against several targets and revealing a few extra details. Copies of the deleted video kept circulating and sped up PoC development. Mitigation advice that had gone to a handful of critical-infrastructure providers from about 23:00 UTC on October 20 may also have leaked. Then at 07:41 UTC on October 21, Chainguard unilaterally broke the embargo and published built images containing the fix, more than six hours before the coordinated release.

The root cause is older than the release. In 2024 PHP went through its first external security audit in years, organized through OSTIF with funding from Germany’s Sovereign Tech Agency and carried out by Quarkslab. While fixing another issue from that audit, a PHP core developer found the first signs of the OOM problem; a potential exploit was theorized that year, but no concrete vectors turned up. Calif began auditing PHP on July 30, 2026 under OpenAI’s Patch the Planet program. On August 11 researcher Ryan A reported an unconditional RCE with the same root cause, OpenAI independently reported the same root cause that day, Wiz submitted its variants on August 24, and OpenAI added more attack vectors on September 18.

AI has also made triage heavier. The PHP Foundation says its security team has published 15 CVEs since July 1 and worked through more than 100 reports that turned out to be invalid, duplicates or not reproducible. PHP is not alone in drowning: Google froze submissions to its open-source bug bounty on October 1 (see Google freezes its open-source bounty).

Fixed versions

The four releases cover the supported 8.2 through 8.5 branches. There are no official builds for 7.4, 8.0 or 8.1.

BranchFixed versionPublished (UTC, 2026-10-21)
8.58.5.1214:06:46
8.48.4.2714:07:28
8.38.3.3614:07:57
8.28.2.3514:09:17

The advisory also lists stopgaps, and it is explicit that none of them makes an installation safe. For 109618: set memory_limit=-1, preferably where applications cannot override it, such as php_admin_value in the FPM pool or Apache config, and check that no pool, directory or application setting puts a finite limit back; keep post_max_size low (8M for sites that take no uploads, 32M if uploads are required, with upload_max_filesize below it); use a container or cgroup limit as an availability boundary with a policy that kills only the affected worker. The advisory adds a counter-intuitive warning here: do not substitute RLIMIT_AS or RLIMIT_DATA, because they can cause the vulnerable allocation failure themselves.

For 109619: set session.upload_progress.enabled=0 and restart every worker, in php.ini, an FPM pool or server configuration that applies before request parsing — not via ini_set() or FPM’s .user.ini. On PHP 8.5, also set fatal_error_backtraces=0 and restart every worker. Remove invalid or deprecated per-request settings that emit diagnostics before initialization; hiding diagnostics with error_reporting, display_errors or @ does not help. Fix attacker-reachable fatal errors and execution timeouts in the application.

Who is exposed

W3Techs measured PHP at 69.3% of websites “whose server-side programming language we know” in its October 22, 2026 crawl. That denominator covers only sites where W3Techs can identify a server-side language, not the whole web. TechCrunch puts it at roughly 70%, more than 33 million sites; The Verge cites VirusTotal’s count of about 3.8 million sites running PHP with at least one port open.

The outages were real. The Verge reported disruption at 4chan, DeviantArt and Wikipedia, precautionary shutdowns at some Dutch and Finnish government agencies, and Pokémon Home and Pokémon Champions going offline (that part relayed from Kotaku). The NSA’s cybersecurity account on X and the UK’s NCSC both advised taking systems offline if an immediate update was not feasible. The Verge also quoted Cloudflare’s CTO saying he was “seeing early attacks emerging.”

Chinese-language guidance has come mainly from cloud vendors. On October 22, MyDrivers relayed a Tencent Cloud risk notice that lists, branch by branch, which versions fall below the fix and which to upgrade to; Tencent says its host security product detects the flaw and its WAF and cloud firewall can block it.

The US CISA Known Exploited Vulnerabilities catalog (catalogVersion 2026.10.21, 1,754 entries) does not yet list either CVE.

What others say

The exploitation timeline is the heart of the dispute. TechCrunch’s Julie Bort, citing OpenAI, wrote on October 21 that researchers found the flaws before attackers did, so “there were no reports of exploits in the wild.” The PHP Foundation’s postmortem likewise says the team monitored and inspected PoCs that appeared after the leak and did not identify any functional exploit at the time of release.

watchTowr’s advisory, published at 14:19 UTC the same day, marks “Exploited in the wild: Yes.” AWS’s CJ Moses is more specific: Amazon Threat Intelligence found a PHP2Shell exploitation attempt in MadPot telemetry dating to October 17, four days before disclosure, from an IP tied to a commercial anonymization network, and saw further attempts against MadPot between 02:00 and 08:00 UTC on October 21 with differing payloads and anonymization infrastructure, suggesting several actors. AWS says it is unclear whether any attempt would have succeeded on a real system, then states that “PHP2Shell is now being broadly exploited in the wild.”

The score dispute has a clean answer. The circulating CVSS 10.0 was wrong, as the PHP Foundation says outright; both the CNA record and NVD carry 9.2 under v4.0 with the vector CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H. NVD separately scores 9.8 under CVSS v3.1, so quote whichever version you mean.

The affected-version range has no single answer. The CNA record lists only 8.2.*, 8.3.*, 8.4.* and 8.5.*, with defaultStatus unaffected. Wiz says every PHP version released in the last decade is affected, going back to 5.4; Calif says the earliest affected path it found dates to PHP 5.4.0; The Verge says roughly 20 years; TechCrunch says since version 5 in 2004. The official fix covers 8.2 through 8.5, with minimal source backports for 7.4, 8.0 and 8.1. The pre-5.4 coverage is a researcher claim, not an official confirmation.

Alexandre Daubois, writing from inside the PHP security team, lists what the leak got wrong: session.upload_progress.enabled=Off belongs to the session path in 109619 and the 109618 advisory never mentions sessions; almost none of the leaked write-ups mentioned memory_limit=-1, the stopgap the advisory puts first; and watchTowr’s version list named PHP 5, 6, 7 and 8, including a PHP 6 that never shipped.

There is a counter-reading of the AI-discovery narrative too. Dead Neurons’ Nick Rogers lays out the timeline: the vulnerable source sat on GitHub for over a decade, Stefan Esser found the original memory_limit interruption bug in 2004, a user reported OOM and skipped temp-file cleanup in the same multipart parser as bug #78876 in November 2019 (later CVE-2019-11048), and the 2024 Quarkslab audit flagged it once more. By Calif’s account, Esser built an exploit in 2004 but did not release it, and two commercial vendors, CORE and Immunity, kept non-public versions; the 2024 audit confirmed the bug without proving exploitation. Rogers’ conclusion: every ingredient was in the training data, but unsteered models did not connect it. A researcher who knew the target’s history asked the question first; the model then collapsed the cost of finding variants and adapting heap layouts from months into days. He cites Mallory’s scan of 1.5 million internet-facing hosts reporting a PHP version, of which 59% (883,717) run end-of-life branches. We covered the same compression of exploit development once before, in XBOW’s six-day Chrome chain.

Our take

The practical message for operators is that the patch window has shrunk from days to hours. AWS’s guidance is worth copying into a runbook: for a critical flaw in an internet-facing system, measure patch and mitigation time in hours, and start any investigation from the earliest known exploitation — for PHP2Shell, at least October 17.

The first minute is mundane. Run php -v or check phpinfo and find out which branch you are on. On 8.2 through 8.5, move to 8.5.12, 8.4.27, 8.3.36 or 8.2.35. If you run distro or LTS vendor packages, check the vendor’s update. If you run official Docker images, change the base image tag and rebuild rather than only bumping composer dependencies.

Three limits are worth stating up front. The mitigation list is not a substitute for patching — the advisory says it reduces exposure to specific attack paths and nothing more. PHP 7.4, 8.0 and 8.1 get minimal source backports only, with no official builds, so teams that compile from source have to weigh the maintenance cost and shared-hosting customers can only wait for their host. And PHP 8.2 reaches end of life on December 31, 2026, which leaves roughly two months before 8.2 sites lose official fixes again.

Some things remain unknown, and should stay that way in print: AWS says it is unclear how the actor behind the October 17 honeypot attempt obtained exploit information early; whether those attempts succeeded is unresolved; and the pre-5.4 exposure rests on researcher demonstrations, with no official builds for those branches. Until those answers arrive, the executable part is to get onto a patched version and align memory_limit and upload settings with the advisory. The patch itself is intelligence, too: a fix PR that drew matching probes about ten minutes after it went public (see probes hit a fix PR in 10 minutes) is a reminder that attackers read diffs.