PHP2Shell Just Turned Every Unpatched Upload Form Into a Shell Lottery
two bugs in PHP core. unauthenticated RCE. default session.upload_progress.enabled=On. patches dropped October 21. Amazon says probing started October 17, during embargo. Cloudflare counted millions of attempts within hours of disclosure. CVE-2026-109618 and CVE-2026-109619. the internet calls it PHP2Shell. your change window calls it “next sprint.” your honeypot already disagrees.
lab-php.local container on gear you own. do not spray multipart upload-progress probes at random internet hosts. that is not research, that is how you get a new hobby involving lawyers. detection and patching are the point.what landed
CISA’s October 21 alert names both CVEs and tells you to update to PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35. anything on 8.1 or earlier has no upstream fix. take it offline or move it. Akamai, JFrog, Datadog, Google Cloud, and AWS all published the same ugly summary within a day:
- CVE-2026-109619: use-after-free in session upload-progress tracking. multipart POST with
PHP_SESSION_UPLOAD_PROGRESScaches rawzval*pointers into session state. free the backing memory, spray, win a call. - CVE-2026-109618: out-of-memory handling leaves request state half-initialized. cleanup treats garbage as gospel.
- CVSS: critical (reported ~9.2). unauthenticated. any endpoint that accepts multipart, even if userland ignores the file, is in scope because the session layer runs first.
- Prereq:
session.upload_progress.enabled=On(factory default) plus a PHP that serves web requests (mod_php, php-fpm, etc.).

step 1: stop guessing, inventory
curl -sI https://your.app/ | grep -iE 'server|x-powered'
php -v
php -i | grep session.upload_progress.enabled
PHP hides inside WordPress, Magento, Laravel, random SaaS appliances, and that one vendor portal nobody admits exists. if X-Powered-By is stripped, you still need package and container inventories. Censys and friends were counting millions of internet-facing PHP hosts on October 21. most were not patched. a shocking number were already EOL.

step 2: lab probe (authorized target only)
the exploit path is a crafted multipart body that exercises upload progress, then corrupts worker memory. public PoCs appeared within hours of the leak. WatchTowr noted many of the early GitHub toys do not actually get RCE. they time, crash, or cosplay. that does not make you safe. Amazon reported pre-disclosure exploitation from anonymized infrastructure, then mass spraying after the embargo lifted. JFrog saw fake PoCs that were just malware for the curious.
in lab, send a boring multipart with PHP_SESSION_UPLOAD_PROGRESS set and confirm the worker still speaks PHP. then patch the container and retest. you are validating exposure and the fix, not collecting skulls.

step 3: what failed exploits still look like
a spray that misses still leaves corpses. php-fpm children exiting signal 11, kernel segfault lines for php-fpm, sudden pool respawns tied to large multipart POSTs. if your journal looks like the lab screenshot, assume someone is knocking. pull request bodies from the WAF, preserve logs, patch, then ask whether any worker spawned a shell before it died.

why defenders care
- default-on feature: you did not “enable” the vuln. PHP shipped it that way.
- pre-auth, pre-routing: userland auth and CSRF checks happen after the session upload-progress code already ran.
- EOL tax: 8.1 and older get no patch. that is a business decision disguised as a version number.
- WAF is a seatbelt, not a force field: AWS and others shipped managed rules. use them while you patch. do not confuse “rule deployed” with “risk closed.”
- post-RCE is boring and lethal: webshell, crypto miner, credential steal, pivot. hunt for PHP spawning shells, unexpected writes under web roots, and new outbound from web pools.
controls that are not theater
- patch to 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 tonight for internet-facing. schedule the rest this week.
- EOL PHP: offline or upgrade. there is no heroic backport coming from the PHP project.
- temporarily disable
session.upload_progress.enabledif a vendor app will tolerate it. verify before you call it a mitigation. - WAF: block or challenge requests carrying
PHP_SESSION_UPLOAD_PROGRESSfrom untrusted clients until patched. rate-limit multipart. - EDR/SIEM: alert on php-fpm/apache children execing
sh,curl,wget,python. alert on SIGSEGV storms correlated with multipart. - inventory: every container image, every shared host, every “temporary” marketing microsite from 2019.
sloth take
we spent twenty years teaching developers to validate uploads. PHP2Shell skipped the developers and went straight for the engine that runs before their code. default progress bars. default sessions. default regret. patch the trains that still get trains. bury the ones that do not. and maybe stop exposing every multipart endpoint on the open internet like it is a community service.
Want a boring inventory of internet-facing PHP before the next core RCE, without a webinar? Book a slot with Dark Edge Consulting.
sources
- CISA: Critical Vulnerabilities in PHP Require Immediate Patching (2026-10-21)
- PHP security advisories GHSA-w8hw-w9fx-j79w / GHSA-6wmf-4rv5-p3rp
- Akamai SIG, JFrog, Datadog Security Labs, Google Cloud, AWS WAF guidance (Oct 21 to 22, 2026)
- SecurityWeek coverage of Amazon / Cloudflare / WatchTowr exploitation telemetry (2026-10-22)
