Sitemap

PHP2Shell Explained: The Decades-Old PHP Bugs That Let One Request Take Over a Web Server

Black October 2026, part 9: PHP itself wasn’t “hacked”. Two critical CVEs in PHP’s core let unauthenticated attackers run code on almost any PHP web server, and attackers tried them before the patch.

Press enter or click to view image in full size
PHP2Shell Explained: The Decades-Old PHP Bugs That Let One Request Take Over a Web Server

TL;DR: On October 21, 2026, PHP released emergency fixes for CVE-2026–109618 and CVE-2026–109619, nicknamed PHP2Shell. Together they cover four memory-safety bugs in PHP’s core that let an unauthenticated attacker leak server memory or run code, using requests that crash PHP mid-request and then reuse the leftover state. Nearly every PHP version from the last decade is affected. Amazon saw an exploitation attempt four days before the bugs were public. Update now.

Press enter or click to view image in full size
How the attacker moved, at a glance (simplified diagram by the author)

First: “PHP was hacked” is misleading

Viral lists say “PHP was hacked.” That isn’t what happened. Nobody breached the PHP project or php.net. This is a vulnerability in the PHP interpreter, and the people at risk are the millions of websites running PHP. That actually makes it more dangerous than a project breach: if you run WordPress, Laravel, Drupal or any PHP app on an unpatched server, you are the target.

The short version for non-specialists

PHP web servers reuse the same worker process for many requests. PHP2Shell abuses that:

  1. The attacker sends a request designed to make PHP run out of memory at a very specific moment.
  2. PHP aborts the request and frees its memory, but forgets to clear a few internal pointers that still point at the freed memory.
  3. The worker keeps running. The attacker’s next request on the same worker uses those stale pointers before PHP resets them.
  4. By shaping what lands in that freed memory, the attacker can read server memory or take control of execution.

All of this happens below your application. No login, no vulnerable plugin, and no bug in your code is needed. Even a simple PHP app on an affected version can be vulnerable.

Press enter or click to view image in full size
The attack chain as described by official sources (diagram by the author)

The technical details

Wiz Research, which reported the bugs, describes four issues grouped under the two CVEs (CVSS up to 9.2). All of them are about how PHP handles fatal errors, especially out-of-memory (OOM) errors, during a request:

CVE-2026–109618: “RCE via OOM corruption”

  • Upload-progress unserializer use-after-free. During upload-progress handling, the session module stores request-owned bookkeeping in the global BG(unserialize). A fatal allocation failure can destroy the request heap while that global is still published, so a later request can consume attacker-controlled memory as if it were live unserializer state.
  • Remote memory disclosure. PHP parses multipart (RFC 1867) uploads during startup. Session upload-progress handling can publish a session ID in PS(id). If an OOM aborts the request before cleanup, PS(id) can point to freed memory, and a later multipart request on the same worker can return heap contents in a PHPSESSID cookie. This path doesn’t even need the app to call session_start().

CVE-2026–109619: “RCE via stale global state”

  • Fatal-error backtrace use-after-free. PHP keeps the last fatal error’s backtrace in EG(last_fatal_error_backtrace). An OOM can free the request heap without clearing it, so the next request’s early diagnostics follow a dangling pointer.
  • OPcache type confusion. If an allocation fails while OPcache is persisting a script, the process-local and shared bookkeeping get out of sync, so another worker can reuse a slot and treat a pointer as the wrong type, corrupting shared OPcache state.

Who is exposed

Every PHP installation that serves web requests: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. Help Net Security reports that mod_php setups face the greatest danger. Wiz says the bugs reach back to PHP 5.4, and every version released in the last decade is affected by at least one of them.

The AI angle

Wiz says these bugs existed for decades. The reason nobody exploited them before is that the exploit chain is hard: it has to be adapted to each target’s PHP version, configuration and memory layout. Wiz credits AI models with lowering that barrier. Models with testing tools could analyze failed attempts and iterate, and a single researcher did in a week what Wiz says would previously have taken a team several months. That cuts both ways: the same speed is available to attackers.

Press enter or click to view image in full size
Incident timeline, compiled from official statements

Exploited before the patch

Amazon Threat Intelligence reported that its MadPot honeypot network recorded a PHP2Shell exploitation attempt on October 17, four days before public disclosure, from an IP tied to a commercial anonymization service. Because the bugs were under embargo, Amazon assessed that a threat actor was likely behind it. How the attacker learned the details early is unknown. CISA later added both CVEs to its Known Exploited Vulnerabilities (KEV) catalog.

Get 0xK1L’s stories in your inbox

Join Medium for free to get updates from this writer.

Press enter or click to view image in full size
The official GitHub security advisory for CVE-2026–109618 in php-src (source: github.com/php/php-src)

What to do

  1. Find every PHP. Run php -v on servers, check container base images, and ask vendors about appliances. Palo Alto Networks said all PAN-OS and Panorama versions are affected, and Fortinet and Cisco published advisories.
  2. Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, or to your Linux distribution’s or LTS vendor’s patched package. Distros received patches before the public release.
  3. PHP 8.1 and older are out of upstream support. PHP published minimal source backports for 7.4, 8.0 and 8.1, but the real fix is upgrading or using an LTS vendor.
  4. Rebuild container images. Restarting a container with an old image doesn’t patch anything.
  5. Can’t patch right now? Cloudflare deployed WAF rules for known exploit vectors, including on free plans, and other providers published mitigations. These are stopgaps. The UK NCSC urges taking offline any system that can’t be fixed immediately.

Detection hints (from Wiz)

  • Unusual multipart requests followed by memory-limit errors or bursts of HTTP 500 responses.
  • Unexpectedly large or malformed PHPSESSID cookies in responses.
  • Unexplained PHP worker churn (workers crashing and restarting).

Application logs may show almost nothing, because the bugs run below the application layer.

Press enter or click to view image in full size
Quick action checklist

Lessons

  • Your runtime is part of your attack surface. Patching your app and plugins isn’t enough if the interpreter underneath is old.
  • Know your versions. An up-to-date inventory (SBOMs for images, configuration management for servers) turns “are we affected?” from days into minutes.
  • Patch windows are shrinking. With AI-assisted exploit development and pre-disclosure attempts, “we’ll patch next maintenance window” is now a real risk for critical CVEs.

Confirmed vs. not confirmed

  • Confirmed: the two CVEs, fixed versions, affected setups, a pre-disclosure exploitation attempt recorded by Amazon, and KEV listing.
  • Not established: how the attacker obtained details before disclosure, and the scale of successful compromises in the wild.

References

This article is part of the “Black October 2026” series: 15 articles, each explaining one security incident from October 2026 for awareness purposes. Facts come from the official statements and researcher reports listed above and are current as of November 2, 2026. Some investigations are still ongoing, so details and numbers may change.