SARVINS Bytes · Interactive security explainer

PHP2Shell: When a Request Outlives Its Memory

How can request handling lead to remote code execution before your app runs?

PHP core · CVE-2026-109618 and CVE-2026-109619 · PHP security team advisories, October 21, 2026 · Research cutoff November 1, 2026

Defensive explainer · Animations are schematic, not attack instructions · Upgrade to a vendor-confirmed fixed build.

One-Minute Overview

The answer: PHP's own request lifecycle can handle data before your application gets control. In two related flaws, an early interruption can leave memory or request-owned state unsafe. Updating PHP is the only complete mitigation identified by the PHP security team.

Problem

Cleanup sees invalid state

An out-of-memory interruption can leave partly initialized state reachable when shutdown begins. Confirmed HTTP RCE affects a demonstrated Apache mod_php path.

Related path

A stale pointer survives

Request-owned state can remain in a worker after its memory is freed; a later request on that same worker can consume it.

Response

Patch the runtime

Update to a fixed PHP build; restart or replace all serving workers and verify vendor backports. Narrow configuration changes buy time, not complete protection.

1 · The OOM path: shutdown reaches invalid state

CVE-2026-109618 concerns an out-of-memory (OOM) exit while request state is only partly initialized. In the demonstrated mod_php path, shutdown can inspect that invalid state before application code starts. A multipart request is one route to the condition, not proof that every request or every PHP deployment is exploitable.

Request parsing → allocation failure → early exit → invalid state during shutdown → possible code execution

Scroll horizontally to inspect the diagram.

OOM interruption exposes partially initialized request state during shutdown

Teaching schematic, not a literal memory layout or exploit recipe. Source: PHP security team, CVE-2026-109618 advisory (P1).

Why the SAPI matters. Apache mod_php calls shutdown even after startup failure. FPM exits the child on that specific startup failure; the advisory finds FPM susceptible by source analysis after startup, but reports no complete FPM exploit for this CVE.

2 · Stale state: the next request meets the old pointer

CVE-2026-109619 is a separate use-after-free risk. One request leaves a reference behind; a later operation on the same worker consumes it before ordinary initialization replaces it. Exploitability depends on a reachable producer, an interruption or repopulation, and an early consumer.

Request A publishes state → request memory is freed → same worker receives request B → early consumer sees stale state

Scroll horizontally to inspect the diagram.

Stale worker state crossing from one request to the next

Schematic: the two requests must reach the same persistent worker; the drawing does not imply every request produces or consumes stale state. Source: CVE-2026-109619 advisory (P2).

The advisory validates session-lifecycle RCE under mod_php and FPM; its FPM case requires a suitable application operation after successful startup. Session upload progress is enabled by default and the vulnerable early path does not require the application to call session_start(). Upload progress is not the only possible consumer.

Scope matters. Suppressing displayed errors or finding no errors in logs does not prove that the early operation is safe.

3 · The fix: protect state across the boundary ★

The PHP patches address both the early OOM exit and stale request-owned global state. The revised OOM handling delays the normal error until a safe point, while a separate hard limit can terminate the process. The state-reset patch prevents affected stale state being reused before initialization.

Scroll horizontally to inspect the diagram.

Patch defers soft OOM to a safe point and resets request state

Teaching schematic: thresholds and timing are conceptual, not measurements. Sources: PHP OOM advisory, stale-state advisory, and resource-limit documentation (P1, P2, P7).

Hard-limit trade-off. The documented hard-limit exit skips shutdown handlers, destructors and output handlers. Test operational behavior and worker replacement after updating.

4 · Action: verify the running build, not just the package

The PHP security team lists fixed releases for all four supported branches. Check the actual web-serving runtime and every container or worker; CLI output alone may describe a different build. PHP releases published October 22, 2026 contain both fixes.

8.2.35

Minimum fixed upstream 8.2 release · P3

8.3.36

Minimum fixed upstream 8.3 release · P3

8.4.27

Minimum fixed upstream 8.4 release · P3

8.5.12

Minimum fixed upstream 8.5 release · P3

Upstream minimum fixed releases for both advisories · PHP ChangeLog, October 22, 2026 (P3)
PHP branchAffected upstreamFirst fixedOperator action
8.2Earlier than 8.2.358.2.35Update; plan supported-branch migration
8.3Earlier than 8.3.368.3.36Update and restart workers
8.4Earlier than 8.4.278.4.27Update and restart workers
8.5Earlier than 8.5.128.5.12Update and restart workers

These are branch-specific upstream thresholds, not a universal version comparison. Distributions may backport fixes without changing the upstream-looking version: verify the vendor advisory, package revision and running image. PHP 8.2 security support ends December 31, 2026; older unsupported branches need migration or vendor guidance, not an assumption of immunity.

While an upgrade is being prepared

Decision rule: patch both flaws, then verify every serving worker. Configuration changes are partial defenses, not substitutes for the fixes.

Evidence gap: the primary advisories establish demonstrated exploitation in tested environments, not how many systems were compromised in the wild as of November 1, 2026.

Sources and evidence

The numbered evidence records below link the vulnerability claims to PHP's own advisories, release history and documentation. Dates for live documentation are access dates; the CVE announcements and PHP releases are dated publications.

  1. PHP advisory: OOM corruption · CVE-2026-109618 · P1
  2. PHP advisory: stale global state · CVE-2026-109619 · P2
  3. PHP 8 ChangeLog: four fixed releases · P3
  4. PHP manual: Session Upload Progress · P4
  5. PHP security team announcement: OOM flaw · P5
  6. PHP security team announcement: stale-state flaw · P6
  7. PHP manual: resource limits · P7
  8. PHP: supported versions · P8
  9. Standing gap: public, independently verified exploitation prevalence was not established by the reviewed primary sources. · P9