← Back to Feed CACHED · 2026-10-21 10:28:37 · CACHE_KEY CVE-2026-109618
CVE-2026-109618 · CWE-416 · Disclosed 2026-10-20

PHP core session.upload_progress multipart handler pre-auth heap use-after-free RCE

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Someone left the front door's deadbolt wired to unlock whenever a stranger slides a flyer through the mail slot

CVE-2026-109618 is one of a pair of heap use-after-free vulnerabilities (collectively branded *php2shell*) in PHP core's session.upload_progress multipart request handler (php_session_rfc1867_callback in ext/session/session.c). The flaw is triggered by a crafted multipart/form-data POST request that includes a form field named PHP_SESSION_UPLOAD_PROGRESS (the default session.upload_progress.name). Because the upload-progress handler fires during PHP's request-initialization phase — before any application code runs — every PHP endpoint on an affected server is reachable, regardless of the application's own authentication or input validation. The vulnerable code path caches raw pointers into a session HashTable; a timed stall between file-data chunks forces a session re-initialization that frees the HashTable while cached pointers still reference it, yielding a classic use-after-free write primitive. Affected versions span PHP 5.4.0 through 8.5.11. session.upload_progress.enabled is On by default in every standard PHP distribution. Expected fixes: PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12 (released or releasing 2026-10-21 14:00 UTC). PHP 8.1 and all older branches are end-of-life and will receive no official patch.

The vendor's CVSS v4.0 9.2 CRITICAL rating is accurate and, if anything, slightly conservative when mapped to real-world conditions. This is an unauthenticated, network-reachable, zero-click, zero-interaction, default-config RCE affecting the single most deployed server-side runtime on the internet. Cloudflare confirmed early exploitation at 07:43 UTC on October 21 — hours before the patch dropped. Multiple PoC repositories are public (ikow/php2shell-poc, weaponized PHP2Shell tool by Calif.IO). watchTowr independently reproduced the chain. The installed base visible on Shodan is ~2.23 million hosts with PHP banners, of which ~884,000 run end-of-life branches that will never be patched. The vendor severity is justified; our reassessed score is 9.8 reflecting confirmed in-the-wild exploitation and the trivially weaponizable attack surface.

"Pre-auth RCE in PHP core, default config, actively exploited — patch or disable today."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Target identification

Attacker scans for any HTTP endpoint returning X-Powered-By: PHP headers or known PHP fingerprints (.php extensions, WordPress/Magento/Drupal signatures). Shodan shows ~2.23 million such hosts. No version check is needed — every version since PHP 5.4.0 with default config is vulnerable. Mass scanning tooling (0xrsydn/php2shell-scan) is already public.
Conditions required:
  • Target runs PHP 5.4.0–8.5.11 with session.upload_progress.enabled=On (default)
  • Target accepts HTTP POST requests on any PHP-handled URI
Where this breaks in practice:
  • None — default PHP installations are vulnerable
  • WAF or reverse proxy might filter multipart traffic, but most do not inspect session.upload_progress.name field content
Detection/coverage: Shodan query http.component:PHP or Censys query (see silascutler/php2shell-censys gist). Nessus/Qualys plugin availability pending; version-based detection is straightforward.
STEP 02

Craft malicious multipart POST

Attacker constructs a multipart/form-data POST body containing a form field whose name matches session.upload_progress.name (default: PHP_SESSION_UPLOAD_PROGRESS). The request also includes a file upload part with a specially crafted boundary and timing stall. The PHP2Shell weaponized tool (Calif.IO) and ikow/php2shell-poc both automate this step. No valid session cookie or authentication token is required.
Conditions required:
  • Knowledge of the default session.upload_progress.name value (public, documented in php.ini)
  • Ability to send a multipart POST to any PHP URI
Where this breaks in practice:
  • A WAF that strips or blocks the PHP_SESSION_UPLOAD_PROGRESS field name in multipart bodies would break this step
  • Cloudflare deployed emergency managed rules (Generic Rules - Anomalous Execution) on 2026-10-21, but these provide partial coverage only
Detection/coverage: WAF logs showing multipart POSTs with PHP_SESSION_UPLOAD_PROGRESS field to unusual endpoints. Cloudflare managed ruleset logs.
STEP 03

Trigger session handler UAF

PHP's request initialization invokes php_session_rfc1867_callback() to process the upload-progress field. The attacker's timed stall between file data chunks causes PHP to re-initialize the session, freeing the internal HashTable. Cached pointers from the earlier callback invocation now reference freed memory. This is the use-after-free (CWE-416) primitive. The entire sequence occurs in PHP core before any application index.php or framework router executes.
Conditions required:
  • PHP's multipart parser processes the request (guaranteed for any Content-Type: multipart/form-data POST)
  • session.upload_progress.enabled is On (default)
Where this breaks in practice:
  • Disabling session.upload_progress.enabled blocks this specific CVE's path (but research indicates the sibling CVE-2026-109619 targets the multipart parser itself and is NOT blocked by this setting)
  • ASLR and PIE on modern Linux make heap layout less predictable, but the PoC reportedly handles this with heap spray
Detection/coverage: Runtime detection is difficult — the corruption happens inside PHP's C internals. Process-level monitoring (Huntress, Florian Roth's process-watcher) can detect the post-exploitation phase.
STEP 04

Achieve code execution as PHP worker

The freed-then-reused heap region is overwritten with attacker-controlled data, hijacking a function pointer or __destruct handler. PHP executes attacker-supplied code in the context of the PHP-FPM worker, php-cgi, or Apache mod_php process — typically running as www-data, apache, or nginx. The attacker now has arbitrary command execution on the server at the privilege level of the web server user.
Conditions required:
  • Successful heap manipulation from step 3
Where this breaks in practice:
  • PHP's disable_functions and open_basedir are bypassed because the exploitation occurs in C-level internals, not in PHP userland
  • SELinux/AppArmor confined profiles for php-fpm *may* limit post-exploitation capabilities but do not prevent the initial code execution
Detection/coverage: EDR/HIDS detecting PHP worker processes spawning child shells (sh, bash, cmd.exe), download utilities (curl, wget, certutil.exe), or reconnaissance commands (whoami, id, ipconfig). Sigma rules for web shell process trees.
STEP 05

Post-exploitation and persistence

Attacker deploys a webshell, establishes a reverse shell, exfiltrates data, or pivots laterally. On e-commerce stacks (Magento, WooCommerce, Shopware), database credentials are in application config files readable by the PHP process. On WordPress sites, wp-config.php yields DB credentials and auth salts. Attackers may inject payment skimmers (Sansec's primary concern), steal customer PII, or pivot to internal networks if the web server has LAN connectivity.
Conditions required:
  • Code execution achieved in step 4
Where this breaks in practice:
  • Network segmentation between DMZ and internal network limits lateral movement
  • Database credential rotation and least-privilege DB accounts limit data exfiltration scope
Detection/coverage: File integrity monitoring on web roots. Database query anomaly detection. Outbound connection monitoring for C2 callbacks.
03 · Compensating Control

1
CRITICAL 9.8→HIGH 7.5
SEVERITY REDUCED
Set session.upload_progress.enabled=0 in php.ini immediately — Add session.upload_progress.enabled=0 to php.ini or per-pool via php_admin_flag[session.upload_progress.enabled] = off in FPM pool configs. Restart PHP-FPM/Apache. This disables the vulnerable php_session_rfc1867_callback code path for CVE-2026-109618 specifically. Warning: research (J4ck3LSyN/lilting.ch) indicates this setting blocks only ONE of the two php2shell CVEs; the sibling CVE-2026-109619 may still be reachable via the multipart parser itself. Apply within hours — this is an active-exploitation scenario overriding the standard noisgate mitigation SLA.
2
CRITICAL 9.8→HIGH 7.0
SEVERITY REDUCED
Deploy WAF rules blocking PHP_SESSION_UPLOAD_PROGRESS in multipart bodies — If behind Cloudflare, enable the emergency managed ruleset (Generic Rules - Anomalous Execution) deployed 2026-10-21. For self-hosted WAFs (ModSecurity, AWS WAF, F5 ASM), add a rule blocking multipart POST bodies containing the string PHP_SESSION_UPLOAD_PROGRESS. Syhunt published Apache mitigation rules. Note: WAF bypass is possible if the attacker can reach the origin directly, and Cloudflare's own advisory notes these rules provide partial coverage. Apply within hours.
3
CRITICAL 9.8→IGNORE 0.0
SEVERITY REDUCED
Patch PHP to 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 — This is the definitive fix. Apply the vendor patch as soon as it is available (scheduled 2026-10-21 14:00 UTC). For distro-packaged PHP, monitor your distribution's security tracker (apt update && apt upgrade php8.x on Debian/Ubuntu; dnf update php on RHEL/Fedora). Given confirmed active exploitation, the noisgate mitigation SLA (patch/mitigate immediately, within hours) applies — do not wait for the standard 3-day CRITICAL window.
4
CRITICAL 9.8→HIGH 8.0
SEVERITY REDUCED
Upgrade or isolate EOL PHP installations (5.x, 7.x, 8.0, 8.1) — These branches will receive no official fix. Upgrade to a supported branch (8.2+) and apply the patch. If upgrade is impossible in the short term, isolate these hosts behind a VPN or WAF that blocks all multipart POST traffic, and add session.upload_progress.enabled=0 as a partial mitigation. Plan the upgrade within the noisgate remediation SLA of 90 days for CRITICAL.
5
CRITICAL 9.8→CRITICAL 9.0
Enable process-level anomaly detection on PHP workers — Configure EDR, osquery, or Florian Roth's process-watcher to alert on PHP worker processes (php-fpm, php-cgi, apache2, httpd) spawning child processes (sh, bash, cmd.exe, curl, wget, python, perl, nc). This does not prevent exploitation but detects successful post-exploitation within seconds, enabling rapid containment. Deploy immediately.
What doesn't work
  • disable_functions in php.ini — does not help because the exploitation occurs in PHP's C-level internals (heap UAF), not via PHP userland function calls. The attacker's code runs before disable_functions restrictions are applied.
  • open_basedir restrictions — same rationale; the memory corruption and code execution happen below the PHP engine's permission model.
  • memory_limit = -1 or similar memory tuning — explicitly confirmed by multiple sources as ineffective against these vulnerabilities.
  • IP-based allowlisting alone — the attack can originate from any IP, and botnet-sourced exploitation makes IP blocking a game of whack-a-mole. Use in combination with field-level WAF rules, not as a standalone control.
  • PHP session.use_strict_mode=1 alone — while recommended as defense-in-depth, this does not prevent the UAF trigger in the upload-progress handler; the vulnerability fires before session validation completes.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationConfirmed. Cloudflare reported early attacks against PHP sites at 07:43 UTC on 2026-10-21, hours before the patch release. Cloudflare deployed emergency WAF rules (Generic Rules - Anomalous Execution). Sansec warns of imminent mass exploitation targeting e-commerce platforms. Not yet in CISA KEV as of 2026-10-21.
Proof-of-Concept AvailabilityPublic and weaponized. ikow/php2shell-poc (researcher Qi Deng, published 2026-10-21) contains verification PoCs and lab setups. A weaponized exploit tool named *PHP2Shell* credited to Calif.IO is circulating. Additional repos on Sploitus: Blue-B/php2shell-guard, 0xrsydn/php2shell-scan, cereZ23/php-up-2026, darkfibr/php2shell-detect. watchTowr independently confirmed reproduction. Syhunt published Apache mitigation rules.
EPSS ScoreNot yet scored — NVD record is still RESERVED. Given the pre-auth RCE nature, default-on configuration, and confirmed exploitation, expect EPSS to land in the 99th+ percentile once scored.
CISA KEV StatusNot listed as of 2026-10-21 10:00 UTC. Given confirmed exploitation by Cloudflare, KEV listing is likely imminent.
CVSS Vector (estimated v3.1)CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8. Vendor rated CVSS v4.0 9.2. Network-reachable, low complexity (weaponized PoC exists), no privileges, no interaction, full CIA impact. The v3.1 mapping yields 9.8 because v4.0's supplemental metrics likely account for attack requirements that compress the score.
Affected VersionsPHP 5.4.0 through 8.5.11 — every version that ships session.upload_progress (enabled by default since PHP 5.4). PHP 8.1 and all older branches are EOL and will receive no official fix.
Fixed VersionsPHP 8.2.35, 8.3.36, 8.4.27, 8.5.12 — scheduled for release 2026-10-21 14:00 UTC. Distro backports (Debian, Ubuntu, RHEL/CentOS, SUSE, Alpine) are pending; track php8.x packages in your distro's security tracker.
Internet Exposure (Shodan)~2.23 million hosts advertising X-Powered-By: PHP headers. ~1.5M disclose a version. ~884,000 hosts (~59% of versioned) run unsupported branches (PHP 5.x, 7.x, 8.0, 8.1) that will never receive a patch. Top countries: US (228,770), China, Japan (55,460), Germany (45,835). Censys query published by silascutler.
Disclosure Timeline2026-10-20: php.net pre-announcement of emergency release. Same day: details leaked, PHP2Shell tool surfaces, CERT-EU assigns CVE IDs. 2026-10-21 07:43 UTC: Cloudflare confirms early exploitation. 2026-10-21 14:00 UTC: scheduled patch release.
Reporting ResearchersOriginal discovery not publicly credited. Exploit tool *PHP2Shell* attributed to Calif.IO. PoC research by Qi Deng (ikow). Independent reproduction by watchTowr. Analysis by Sansec, Huntress, J4ck3LSyN (lilting.ch). Mitigation tooling by Syhunt.

Sources.

  1. Sansec — Critical PHP RCE: CVE-2026-109618 and CVE-2026-109619
  2. Huntress — Rapid Response: php2shell Leaked Critical PHP Vulnerabilities
  3. php.net — Upcoming Critical PHP Security Release announcement
  4. Phoenix Security — PHP Core RCE CVE-2026-109618 & 109619 exposure analysis
  5. ikow/php2shell-poc — PoC and analysis (GitHub)
  6. Brandefense — PHP2Shell advisory and timeline
  7. lilting.ch — Disabling session.upload_progress before the php2shell patch
  8. Syhunt — Emergency Apache mitigation toolkit for php2shell
05 · The Call

Final Verdict
= UNCHANGED to CRITICAL (9.8/10)

Why this verdict

  • Pre-auth, zero-click, network-reachable RCE on default config. The attack requires only the ability to send an HTTP POST to any PHP endpoint. No authentication, no user interaction, no non-default settings. CVSS:3.1 base is 9.8. The vendor's v4.0 9.2 is fair within that framework; under v3.1 this maps higher.
  • Confirmed in-the-wild exploitation. Cloudflare detected attacks at 07:43 UTC on 2026-10-21, before the patch was available. This is not theoretical — exploitation is happening now. Multiple weaponized PoCs are public.
  • Installed base is the largest server-side runtime on the internet. Shodan shows 2.23M PHP hosts with public banners. The true number is far higher (many suppress headers). WordPress alone powers ~40% of websites. The blast radius of a PHP core RCE is effectively internet-scale.
  • Role multiplier: web application tier. PHP is canonically an internet-facing application runtime. ~100% of PHP installations exist to serve HTTP traffic. The affected component (session.upload_progress) is enabled by default and fires for *any* multipart POST — the application doesn't need to use upload progress. On e-commerce platforms (Magento, WooCommerce, Shopware), the blast radius is payment-card theft and mass PII exfiltration (supply-chain-scale for Sansec's threat model). On WordPress sites with DB credentials in wp-config.php, the blast radius extends to full database compromise. On hosting providers, a single shared-hosting server may run hundreds of PHP sites. The high-value-role floor is CRITICAL because PHP *is* the network-edge application layer for the majority of the web.
  • Role multiplier: hosting infrastructure. Shared hosting providers (GoDaddy, Hostinger, etc.) run thousands of customer sites per PHP-FPM pool. A single exploitation yields access to all co-tenanted sites on that instance — fleet-scale blast radius.
  • 884,000 internet-facing hosts on EOL PHP branches will never receive an official patch. These hosts remain permanently exploitable unless they upgrade major PHP versions or apply the ini mitigation. This is a long-tail catastrophe for the internet.
  • Zero friction in the attack chain. No step requires elevated access, non-default config, or chaining with another vulnerability. The attack is a single HTTP request to any PHP endpoint. disable_functions and open_basedir do not help because exploitation occurs in PHP's C internals, not userland.

Why not higher?

A 9.8 is effectively the ceiling for a use-after-free RCE. A 10.0 would require scope change (e.g., hypervisor escape) or a wormable propagation mechanism. While the blast radius is enormous, each exploitation instance is a single-host compromise at the web-server privilege level, not an automatic lateral-movement chain. Post-exploitation still requires attacker effort to pivot.

Why not lower?

Every downward-pressure factor is absent. The attack is pre-auth (no privilege requirement), default-config (no non-standard setup needed), zero-click (no user interaction), network-reachable (internet-facing by definition), and actively exploited in the wild with public weaponized tooling. The affected software is the most widely deployed server-side runtime on earth. There is no realistic friction to cite. Dropping below CRITICAL would be negligent given confirmed exploitation and the scope of the installed base.

06 · Verification

Crowdsourced verification payload.

Run this script on each target PHP host as any user who can execute php -v and read php.ini. Example: chmod +x php2shell-check.sh && ./php2shell-check.sh. No root required unless PHP is installed in a restricted path. The script checks the installed PHP version against known-fixed releases and inspects the session.upload_progress.enabled runtime setting.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash\n# php2shell-check.sh — CVE-2026-109618 exposure checker\n# Usage: ./php2shell-check.sh\n# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN\n\nset -euo pipefail\n\nPHP_BIN=\"${PHP_BIN:-php}\"\n\nif ! command -v \"$PHP_BIN\" &>/dev/null; then\n  echo \"UNKNOWN — php binary not found in PATH. Set PHP_BIN=/path/to/php and retry.\"\n  exit 2\nfi\n\nVERSION_RAW=$($PHP_BIN -r 'echo PHP_VERSION;' 2>/dev/null)\nif [[ -z \"$VERSION_RAW\" ]]; then\n  echo \"UNKNOWN — could not determine PHP version.\"\n  exit 2\nfi\n\nMAJOR=$(echo \"$VERSION_RAW\" | cut -d. -f1)\nMINOR=$(echo \"$VERSION_RAW\" | cut -d. -f2)\nPATCH=$(echo \"$VERSION_RAW\" | cut -d. -f3 | sed 's/[^0-9].*//')\n\n# Check session.upload_progress.enabled\nSUP=$($PHP_BIN -r 'echo ini_get(\"session.upload_progress.enabled\");' 2>/dev/null || echo \"unknown\")\n\necho \"PHP Version: $VERSION_RAW\"\necho \"session.upload_progress.enabled: $SUP\"\necho \"---\"\n\n# Fixed versions: 8.2.35, 8.3.36, 8.4.27, 8.5.12\nVULNERABLE=0\n\nif (( MAJOR < 8 )); then\n  echo \"VULNERABLE — PHP $VERSION_RAW is end-of-life and will not receive a patch for CVE-2026-109618.\"\n  echo \"Action: Upgrade to PHP 8.2.35+, 8.3.36+, 8.4.27+, or 8.5.12+.\"\n  VULNERABLE=1\nelif (( MAJOR == 8 )); then\n  case \"$MINOR\" in\n    0|1)\n      echo \"VULNERABLE — PHP $VERSION_RAW is end-of-life (8.0/8.1). No official patch available.\"\n      echo \"Action: Upgrade to a supported PHP branch and apply the fix.\"\n      VULNERABLE=1\n      ;;\n    2)\n      if (( PATCH < 35 )); then\n        echo \"VULNERABLE — PHP $VERSION_RAW is below the fixed version 8.2.35.\"\n        VULNERABLE=1\n      else\n        echo \"PATCHED — PHP $VERSION_RAW includes the fix (>= 8.2.35).\"\n      fi\n      ;;\n    3)\n      if (( PATCH < 36 )); then\n        echo \"VULNERABLE — PHP $VERSION_RAW is below the fixed version 8.3.36.\"\n        VULNERABLE=1\n      else\n        echo \"PATCHED — PHP $VERSION_RAW includes the fix (>= 8.3.36).\"\n      fi\n      ;;\n    4)\n      if (( PATCH < 27 )); then\n        echo \"VULNERABLE — PHP $VERSION_RAW is below the fixed version 8.4.27.\"\n        VULNERABLE=1\n      else\n        echo \"PATCHED — PHP $VERSION_RAW includes the fix (>= 8.4.27).\"\n      fi\n      ;;\n    5)\n      if (( PATCH < 12 )); then\n        echo \"VULNERABLE — PHP $VERSION_RAW is below the fixed version 8.5.12.\"\n        VULNERABLE=1\n      else\n        echo \"PATCHED — PHP $VERSION_RAW includes the fix (>= 8.5.12).\"\n      fi\n      ;;\n    *)\n      echo \"UNKNOWN — PHP 8.$MINOR is not a recognized branch. Verify manually.\"\n      exit 2\n      ;;\n  esac\nelse\n  echo \"UNKNOWN — PHP $MAJOR.x is newer than expected. Verify manually.\"\n  exit 2\nfi\n\nif (( VULNERABLE == 1 )); then\n  if [[ \"$SUP\" == \"\" || \"$SUP\" == \"0\" ]]; then\n    echo \"NOTE: session.upload_progress.enabled is OFF — partial mitigation for CVE-2026-109618 is in place.\"\n    echo \"WARNING: This does NOT mitigate the sibling CVE-2026-109619. Patching is still required.\"\n  else\n    echo \"WARNING: session.upload_progress.enabled is ON (default). System is fully exposed.\"\n    echo \"Immediate action: Set session.upload_progress.enabled=0 in php.ini and restart PHP.\"\n  fi\n  exit 1\nelse\n  exit 0\nfi