OrbitalReg
Sign in →

Supply-chain case study

Patched · released 21 Oct 2026, 14:00 UTC

PHP2Shell: two 9.2 RCEs in every PHP since 5.4 — and the runtime hiding in your images.

On 20 October 2026 the PHP security team gave one day's notice of an emergency release for two critical vulnerabilities, CVE-2026-109618 and CVE-2026-109619, each rated CVSS 4.0 9.2 and exploitable without authentication. Then the details leaked ahead of the coordinated disclosure. Every PHP release since 5.4 is in scope, and Sansec expected mass exploitation within fifteen minutes of the fix going public. The fix shipped at 14:00 UTC as PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35; Cloudflare reported early attacks the same day. Here is what the advisory says, what it means for the PHP you don't know you run — and, honestly, what a registry can and cannot do about a runtime CVE.

If you run PHP anywhere internet-facing, patch now — the fixes are out and so are the attacks. Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 and restart every worker, internet-facing first. Then inventory every PHP runtime you operate — not just the apps you know about, but the PHP inside container images, managed hosting, and third-party products that bundle it (WordPress, Drupal, Joomla, Magento, and the appliances nobody remembers run PHP). The PHP project is explicit that "there are no complete mitigations, updating is the only safe choice." On PHP 8.1 or older: apply your distribution's backport or the project's minimal source patches, and start the migration — 8.2 itself goes end-of-life on 31 December 2026.

What is confirmed

A broken embargo and a very large blast radius.

The confirmed facts are few and all of them are bad. Two remote-code-execution flaws in the PHP interpreter itself, each CVSS 4.0 9.2, both exploitable without authentication according to CERT-EU. The PHP security team's own notice reserved the right to release early "should details of either vulnerability become public, or should evidence of active exploitation appear in the wild" — and the details did become public, which is why the name PHP2Shell exists at all. WatchTowr reproduced CVE-2026-109618 and confirmed the vulnerabilities "are indeed real" while withholding technical specifics until the patch. The advisory published with the release describes two distinct bugs in request lifecycle handling — one triggered by out-of-memory conditions, one by state that outlives its memory — detailed below.

What makes this a supply-chain story rather than a web-app story is the shape of the affected population. PHP is not a dependency you declare; it is a runtime you inherit. It arrives inside php:* and wordpress:* container images, inside distribution packages, inside managed-hosting stacks, and inside commercial products that embed it without saying so. JFrog's own guidance on this CVE makes the point bluntly: a dependency inventory is not enough, and vendors "may backport security fixes without changing the upstream version number" — so a scanner that matches upstream version strings will flag patched systems as vulnerable and, worse, has no way to know about runtimes it never saw.

Before the release neither WatchTowr nor Huntress had observed exploitation in the wild; by the afternoon of 21 October, Cloudflare's CTO reported "early attacks emerging", and exploit code of unverified provenance was circulating publicly. The window was, as predicted, measured in hours. The Log4Shell precedent is instructive in the wrong way: a critical, trivially triggered flaw in a ubiquitous runtime became what the Cyber Safety Review Board called an "endemic vulnerability", still being exploited years later because the hard part was never the patch — it was finding every place the vulnerable component lived.

Fixed versions & root cause — from the 21 Oct release

Fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older receive no updates from the project; the security team published minimal source backports for 7.4, 8.0 and 8.1, and distributions and LTS vendors may ship their own. The volunteer rpms.remirepo.net repository had no updates on release day.

CVE-2026-109618 — RCE via OOM corruption. Out-of-memory handling can interrupt PHP while internal request data is only partially initialised; request cleanup then treats the invalid data as valid. CVE-2026-109619 — RCE via stale global state. Request-owned internal state can survive after its backing memory has been freed, and a later request on the same worker may use it before normal initialisation resets it.

At risk: every PHP installation serving web requests — PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP, LiteSpeed. The project rates mod_php highest, with a demonstrated unauthenticated exploit that fires before any application code runs. Partial mitigations only (memory_limit=-1 with a small post_max_size for 109618; session.upload_progress.enabled=0 for 109619, which "blocks the confirmed session paths but not other variants") — none of them makes an installation safe.

2 × 9.2

critical, unauthenticated RCEs in the PHP interpreter (CVSS 4.0)

5.4+

every PHP release since 2012 in scope; 8.1 and older get source backports only

24 h

from advance notice to release — and the details leaked inside that window

15 min

Sansec's estimate from patch publication to mass exploitation

The OrbitalReg defence

What a curated registry actually changes.

✓Inventory you didn't have to build

JFrog's "inventory every runtime" advice is a scramble if your images were pulled from Docker Hub by whoever needed them. If they flowed through your registry, the SBOM index already answers "which images contain a PHP runtime, which version, pulled by whom" — including the PHP inside a vendor appliance image nobody tagged as PHP.

✓Pull-gate on critical, fleet-wide

The moment the CVEs are in the feeds with affected versions, a policy on critical CVEs makes every pull of a vulnerable php base image or package return 403 — so no new deployment, rebuild or autoscaling event ships the hole while you patch, and patched tags flow through untouched.

✓Distro-aware scanning, not string matching

The backport problem is exactly why OrbitalReg scans images with Trivy and Grype, which read distribution security trackers rather than comparing upstream version strings. A Debian package that carries the fix under an unchanged version number is recognised as fixed; a scanner that only knows "8.3.x < fixed" is wrong in both directions.

✓Audit trail for the long tail

Log4Shell went endemic because nobody could enumerate the exposure. The append-only pull log is that enumeration, kept for you: every image and package that contained the affected runtime, who pulled it, when, and whether it has since been pulled again as a fixed version.

The honest caveat. A registry controls what gets pulled next; it does not patch what is already serving traffic. PHP2Shell is, first and foremost, a fleet-patching and change-management problem — the fifteen-minute window Sansec describes is between patch and exploit, and only your rollout speed closes it. A pull-gate also only bites once affected versions are in the advisory feeds, which lags the release by hours; until then a sensible policy is to hold all new PHP image tags in quarantine rather than guess. And for PHP 8.1 and older there may be no fixed version to gate toward at all — the only control there is migration, and no tooling makes that fast. What the registry gives you is the thing Log4Shell responders lacked: a complete list of where the runtime lives, and a switch that stops the vulnerable version spreading while you work the list.

Timeline & identifiers

What to track while this unfolds.

Compiled from the PHP security advisory and release notes, JFrog Security Research, SecurityWeek, Sansec and Tenable reporting of 20–21 Oct 2026. Exploitation is ongoing; cross-check the sources below before acting.

Sources

Do you know every image that carries a PHP runtime?

Put the inventory and the pull-gate in place before the next runtime CVE.

Rico, the founder, walks through SBOM indexing, critical-CVE pull-gates and the audit trail for container images and distro packages — the controls that turn "inventory everything" from a scramble into a query.