PHP2Shell (CVE-2026-109618 & CVE-2026-109619): Critical PHP RCE Patch Guide

PHP2Shell (CVE-2026-109618 & CVE-2026-109619) exposes 70% of the web to unauthenticated PHP RCE and memory leaks. Check fixed versions, IOCs, and mitigations.

William OGOU
23 min read
Share
On this page11 sections

On October 21, 2026, at 14:00 UTC, the PHP project shipped emergency out-of-cycle security updates to patch PHP2Shell (CVE-2026-109618 and CVE-2026-109619), a pair of critical memory-safety flaws rated 9.2 on the CVSS v4.0 scale. Because both vulnerabilities reside directly in the core PHP runtime engine rather than in any framework or CMS, they expose roughly 70% of all websites on the Internet to unauthenticated Remote Code Execution (RCE) and Heartbleed-style worker memory disclosure even when the web application’s own code is completely secure.

Every PHP release over the past decade stretching all the way back to PHP 5.4 is affected by at least one of the flaws. Even a three-line "Hello World" PHP script on a vulnerable server can be compromised remotely without authentication.

Here is the complete technical breakdown of how the four underlying PHP2Shell bugs work, which patched versions you must install (8.5.12, 8.4.27, 8.3.36, and 8.2.35), why the viral session.upload_progress.enabled=0 workaround will not save you, and how to hunt for exploitation indicators in your logs.

Key Takeaways: What You Need to Know Right Now

  • Two Critical Engine CVEs (CVSS 9.2): Tracked as CVE-2026-109618 and CVE-2026-109619 (initially leaked on Hacker News on October 20 with an unofficial CVSS 10.0 claim, prompting PHP to pull its coordinated release forward by 24 hours).
  • Pre-Auth RCE + Heartbleed-Style Memory Bleed: Unauthenticated attackers can execute arbitrary code on the server or silently read live PHP worker heap memory leaking passwords, API keys, JWTs, database credentials, and TLS certificates belonging to other users’ requests without ever needing RCE.
  • Patched PHP Versions: Upgrade immediately to PHP 8.5.12, PHP 8.4.27, PHP 8.3.36, or PHP 8.2.35. For End-of-Life (EOL) branches, the PHP security team released emergency source backports for PHP 7.4, 8.0, and 8.1.
  • All Web SAPIs Affected: Apache mod_php (highest risk, where an exploit fires before any application code runs), PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed are all impacted.
  • Updating WordPress, Drupal, or Laravel Does Not Fix It: You must patch the underlying PHP runtime package or container image and restart all PHP workers (php-fpm, apache2/httpd).
  • Viral php.ini Workaround Is Incomplete: Setting session.upload_progress.enabled=0 blocks only one specific session entry path in CVE-2026-109619 and does nothing to stop CVE-2026-109618 or other exploit variants.
  • AI Inflection Point: Discovered by Wiz Research, Calif, and OpenAI’s Codex Security team using Wiz Atlas, Gemini 4 Argon, and GPT-5.6 Sol, which compressed months of multi-bug heap exploitation engineering across WordPress, Drupal, and Joomla into a single week.

Affected and Fixed PHP Versions (CVE-2026-109618 & CVE-2026-109619)

The PHP project only publishes official point releases for its four actively supported branches (8.2 through 8.5). However, because roughly 884,000 internet-facing hosts (59% of the 1.5 million version-reporting PHP servers on Shodan, according to security firm Mallory, plus another 740,000 hosts hiding their version banner) still run PHP 8.1 or older, the PHP security team also published official source backports for PHP 7.4, 8.0, and 8.1.

PHP BranchVulnerable VersionsFirst Fixed VersionOfficial PHP Support Status
PHP 8.5< 8.5.128.5.12Active support until December 31, 2027
PHP 8.4< 8.4.278.4.27Active support until December 31, 2026
PHP 8.3< 8.3.368.3.36Security fixes only until December 31, 2027
PHP 8.2< 8.2.358.2.35Security fixes only until December 31, 2026
PHP 8.1All 8.1.xSource backport / OSEnd of Life (official source patch + distro backport)
PHP 8.0All 8.0.xSource backport / OSEnd of Life (official source patch + distro backport)
PHP 7.4All 7.4.xSource backport / OSEnd of Life (official source patch + distro backport)
PHP 5.4–7.3All versionsNo upstream patchEnd of Life upgrade or isolate immediately

Don’t Get Fooled by Linux Distribution Version Numbers

Linux distributions and long-term support vendors (Debian, Ubuntu, RHEL, AlmaLinux, Rocky Linux, Alpine, and CloudLinux) received the patches under embargo ahead of the 14:00 UTC disclosure. Because enterprise Linux distributions backport security diffs into existing package versions rather than bumping the upstream version number, php -v may still display an older string like PHP 8.2.24 or PHP 8.1.2-1ubuntu2.21 even after patching.

Always verify the patch against your package changelog rather than relying on the version banner:

bash
# Debian / Ubuntu: verify CVE-2026-109618 and CVE-2026-109619 in the installed package changelog
apt-get changelog php-common | grep -E "CVE-2026-109618|CVE-2026-109619"
dpkg-query -W -f='${Package} ${Version}\n' 'php*'

# RHEL / Rocky / AlmaLinux / Amazon Linux: inspect RPM changelog
rpm -q --changelog php-common | grep -E "CVE-2026-109618|CVE-2026-109619"

Who Is Vulnerable? Apache mod_php vs. PHP-FPM, CGI, FrankenPHP & LiteSpeed

Every PHP Server API (SAPI) that processes web requests is vulnerable to PHP2Shell, including Apache mod_php, PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed (lsphp), as well as PHP bundled inside control panels like cPanel and Plesk or hardware appliances.

However, the mechanics of exploitation differ depending on how your web server manages PHP worker lifecycles:

Deployment ArchitectureExposure LevelExploitation Behavior
Apache mod_phpCriticalHighest risk. Demonstrated unauthenticated RCE triggers in the request startup window before any application code runs. Worker state persists across requests in-process.
PHP-FPM (NGINX / Apache / Caddy)High–CriticalVulnerable to both CVEs and unauthenticated memory disclosure. FPM terminates workers on certain early setup crashes, but cross-worker OPcache and app-assisted RCE chains work.
FrankenPHP / LiteSpeed / CGIHigh–CriticalVulnerable across request-handling and shared-memory paths. Long-running worker processes and shared OPcache segments allow state corruption to persist across requests.
PHP CLI only (no web SAPI)LowNot directly reachable over HTTP unless untrusted multipart or request inputs are fed into a persistent PHP daemon.

Wiz Research combined the vulnerabilities into a single exploit script (php2shell) and demonstrated unauthenticated pre-auth RCE against unmodified, out-of-the-box container images of WordPress (wordpress:latest), Drupal (drupal:latest), and Joomla (joomla:latest). Those CMS platforms were chosen merely as representative targets the vulnerable code executes inside the Zend/PHP engine itself.

Technical Deep Dive: How the 4 PHP2Shell Memory-Safety Bugs Work

At the root of PHP2Shell is a decade-old architectural flaw in how the PHP engine handles fatal errors specifically Out-of-Memory (OOM) allocation failures during request processing.

When PHP encounters a fatal OOM error mid-request, it aborts execution and tears down the per-request heap (zend_mm_heap). However, across multiple subsystems, PHP failed to reset global pointers or shared-memory indices that had already been updated before the allocation failed. When the worker process survives (or shares OPcache memory with sibling workers) and accepts a subsequent HTTP request, it reuses those dangling pointers (Use-After-Free) or desynchronized shared-memory slots (Type Confusion).

Wiz Research detailed four distinct exploitable primitives grouped under the two CVEs (and noted that additional variants exist across the codebase, all of which are neutralized by PHP’s core engine patch):

CVE IdentifierEngine PrimitivePrimary ImpactWiz Research Demonstration
CVE-2026-109618Upload-progress unserializer Use-After-FreeArbitrary memory corruption & pre-auth RCEUnauthenticated RCE on WordPress, Drupal, and Joomla
CVE-2026-109618Session PS(id) Use-After-FreeHeartbleed-style remote process-memory disclosureApplication-agnostic leak of live worker heap via PHPSESSID
CVE-2026-109619Fatal-error backtrace Use-After-FreeCross-request memory corruption & pre-auth RCEUnauthenticated RCE on Drupal
CVE-2026-109619OPcache map_ptr cross-worker Type ConfusionShared-memory state corruption & pre-auth RCEUnauthenticated RCE on WordPress

1. Upload-Progress Unserializer Use-After-Free (CVE-2026-109618)

During the pre-initialization window before a PHP script even starts executing PHP’s Session module can decode serialized session data while processing RFC 1867 file upload progress. During decoding, the unserializer stores request-owned bookkeeping pointers inside the global structure BG(unserialize).

  1. Triggering the Dangling State: An attacker sends a crafted request that triggers an Out-of-Memory fatal allocation failure while BG(unserialize) is active. PHP aborts the request and frees the request heap, leaving BG(unserialize) populated with dangling pointers.
  2. Heap Reclamation & RCE: On a later request routed to the same worker process, the attacker shapes heap allocations so attacker-controlled data occupies the freed address. PHP consumes that reclaimed memory as live unserializer bookkeeping, giving the attacker a powerful write/corruption primitive.
  3. Bypassing ASLR: By pairing this Use-After-Free with the memory disclosure primitive below to eliminate address space layout randomization (ASLR) uncertainty, researchers achieved reliable, unauthenticated RCE on WordPress, Drupal, and Joomla.

2. Heartbleed-Style Remote Process-Memory Disclosure (CVE-2026-109618)

Much like MongoBleed (CVE-2025-14847) and OpenSSL’s infamous 2014 Heartbleed bug, the second primitive in CVE-2026-109618 allows an unauthenticated attacker to bleed live process memory straight over the network without needing code execution:

  1. Early RFC 1867 Parsing: PHP parses multipart/form-data bodies during request startup, prior to normal module initialization.
  2. Dangling PS(id) Pointer: Session upload-progress handling initializes Session state in this early window and publishes a session identifier pointer in PS(id). If an OOM error aborts the request before cleanup finishes, PHP destroys the request heap while leaving PS(id) pointing to the freed memory chunk.
  3. Exfiltration via PHPSESSID Cookie: When a subsequent multipart request hits the same worker, execution reaches the upload-progress cleanup path before normal Session initialization resets PS(id). PHP trusts the stale pointer and length field as a valid zend_string and URL-encodes the raw heap contents directly into a Set-Cookie: PHPSESSID=... HTTP response header.

Crucially, this attack works even if the target application never calls session_start(). Attackers can repeatedly read attacker-sized regions of live worker heap memory containing plaintext passwords, database connection strings, Authorization headers, session tokens, API keys, and private certificates from other users’ requests.

3. Fatal-Error Backtrace Use-After-Free (CVE-2026-109619)

In affected versions (including PHP 8.5), the engine retains the backtrace of the most recent fatal error inside the executor global EG(last_fatal_error_backtrace).

When a fatal OOM error destroys the request heap, PHP fails to undefine EG(last_fatal_error_backtrace). The worker process survives into the next request holding a global pointer to freed memory. If that worker emits a diagnostic message early in the subsequent request before the executor reinitializes EG(last_fatal_error_backtrace) PHP attempts to destroy or update the dangling backtrace, following attacker-reclaimed heap memory into controlled memory corruption and pre-authentication RCE.

4. OPcache Cross-Worker Type Confusion (CVE-2026-109619)

Unlike the first three bugs, which abuse state within a single surviving worker, the fourth primitive corrupts shared memory across all PHP-FPM or Apache workers via OPcache:

  1. Frontier Desynchronization: OPcache stores compiled PHP bytecode and structures in shared memory (SHM) and assigns indices into per-worker runtime-pointer maps (map_ptr). Workers coordinate these indices using a shared frontier.
  2. Mid-Persistence OOM: Inside zend_accel_script_persist(), PHP advances the process-local frontier CG(map_ptr_last) first, and publishes the updated shared frontier only after persistence completes.
  3. Cross-Worker Type Confusion: If an allocation failure interrupts zend_accel_script_persist() between those two steps, the process-local advance stays in place and partially persisted objects reference map_ptr slots that the shared OPcache state still considers free. When a sibling worker reuses one of those slots for a completely different runtime object, stale shared metadata resolves to a pointer of the wrong type triggering cross-worker type confusion and unauthenticated RCE.

Why session.upload_progress.enabled=0 Will Not Save You

In the hours between the October 20 Hacker News leak and the October 21 14:00 UTC patch release, a single configuration line went viral on X and security forums as a purported fix:

ini
; WARNING: Incomplete mitigation   does NOT block CVE-2026-109618 or non-session variants
session.upload_progress.enabled = 0

Tokyo-based security firm GMO Flatt Security initially floated the setting early on October 21 as a probabilistic mitigation, before walking it back at 05:00 UTC to warn that attacks bypassing it were expected. PHP core developers were even more direct:

  • Gina Peter Banyard (PHP core developer funded by the PHP Foundation): “The only thing I can say is that the only mitigation is patching/upgrading PHP. I sadly know too much.”
  • Joe Ferguson (PHP 8.6 Release Manager): “ini settings won’t save you.”

Here is why relying on session.upload_progress.enabled=0 leaves your servers exposed:

  1. It Only Touches One Entry Path: Disabling session upload progress blocks the confirmed RFC 1867 session upload-progress path in CVE-2026-109619, but it does not mitigate CVE-2026-109618, the EG(last_fatal_error_backtrace) Use-After-Free, the OPcache map_ptr type confusion, or other OOM state-corruption variants in the engine.
  2. The .user.ini and CLI Verification Trap: Many administrators added session.upload_progress.enabled=0 to .user.ini or checked it with php -i at the terminal. Under Apache mod_php, .user.ini files are completely ignored (they are read only by CGI/FastCGI SAPIs and cached for user_ini.cache_ttl = 300 seconds). Furthermore, running php -i inspects the CLI SAPI configuration (/etc/php/8.x/cli/php.ini), not the running php-fpm pool or Apache module serving web traffic.

Should you still turn session.upload_progress.enabled=0 off if you don’t use upload progress bars? Yes PHP’s own documentation recommends disabling it when unused, and it closes one confirmed vector while you stage your upgrade. Just do not mistake it for a patch.

How to Patch PHP2Shell and Official Temporary Mitigations

Step 1: Upgrade the PHP Runtime and Restart All Workers

Updating your CMS or framework (composer update, WordPress core auto-update, etc.) does not touch the PHP binary. Update the system packages or container base images and immediately restart the web server and PHP worker pools:

bash
# Ubuntu / Debian (including Ondřej Surý PPA)
sudo apt-get update && sudo apt-get install --only-upgrade -y 'php*'
sudo systemctl restart php8.5-fpm php8.4-fpm php8.3-fpm php8.2-fpm apache2 nginx 2>/dev/null || true

# RHEL / Rocky / AlmaLinux / Fedora
sudo dnf upgrade --refresh -y 'php*'
sudo systemctl restart php-fpm httpd nginx 2>/dev/null || true

For containerized workloads (Docker / Kubernetes), rebuild and redeploy against the patched upstream images (php:8.5.12-fpm, php:8.4.27-fpm, php:8.3.36-fpm, php:8.2.35-fpm, or the updated wordpress:latest / drupal:latest images built after 14:00 UTC on October 21, 2026).

Step 2: Review Memory Settings After Patching (Breaking Behavior Change)

Pay close attention to this post-patch change noted in the PHP security advisory: the PHP2Shell patch introduces a new hard memory limit inside the engine.

When a PHP process hits this new hard memory ceiling, it immediately terminates the worker process and stops PHP shutdown handlers (register_shutdown_function) from running. After upgrading to 8.5.12, 8.4.27, 8.3.36, or 8.2.35, audit your memory_limit and post_max_size settings against your application’s legitimate peak memory usage so normal file uploads or heavy requests do not abruptly kill workers.

Step 3: Official Partial Mitigations (If You Cannot Patch Immediately)

If you are locked in an emergency change freeze or awaiting a vendor appliance update, the official PHP advisory and CERT-EU recommend the following layered stopgaps to reduce exposure until the binary update is applied:

1. Mitigations for CVE-2026-109618

  • Lock memory_limit = -1 or prevent overrides, and clamp request sizes at the edge: The official advisory notes that setting memory_limit = -1 in php.ini (via php_admin_value[memory_limit] = -1 so applications cannot override it via ini_set()) prevents attackers from intentionally triggering soft memory_limit bailouts mid-request, provided you strictly enforce a low post_max_size and strict request-body caps at your reverse proxy or web server (client_max_body_size in NGINX, LimitRequestBody in Apache) so a single request cannot exhaust physical host RAM.
  • CRITICAL WARNING Do NOT use RLIMIT_AS or RLIMIT_DATA: PHP explicitly warns administrators not to use OS-level RLIMIT_AS or RLIMIT_DATA process limits as a substitute for memory_limit. When the kernel denies mmap/brk allocations under RLIMIT, it triggers the exact same vulnerable Out-of-Memory allocation failure path inside the PHP engine.

2. Mitigations for CVE-2026-109619

Add the following directives to your active web SAPI php.ini (or php-fpm pool configuration using php_admin_flag) and restart every worker:

ini
; Disable RFC 1867 session upload progress
session.upload_progress.enabled = 0

; Required on PHP 8.5 to block the EG(last_fatal_error_backtrace) UAF path
fatal_error_backtraces = 0

3. Reverse Proxy & WAF Hardening (Beware the PHP 8.4 request_parse_body() Trap)

If your application does not accept file uploads or multipart/form-data submissions, you can block multipart/form-data requests at NGINX, Apache, or your WAF before they ever reach PHP.

Do not restrict this rule to POST requests only. PHP 8.4 introduced request_parse_body(), which parses multipart/form-data payloads on PUT, PATCH, and other HTTP methods as well. Block the Content-Type header across all HTTP methods and enforce strict body size limits:

nginx
# NGINX stopgap: cap request body size and block multipart/form-data across ALL methods
# WARNING: Only block multipart/form-data on endpoints that do not require file uploads
server {
    listen 443 ssl http2;
    server_name app.example.com;

    # Keep request bodies small to prevent OOM heap grooming
    client_max_body_size 1m;

    # Optional: completely block multipart requests regardless of HTTP method (POST, PUT, PATCH, etc.)
    if ($http_content_type ~* "multipart/form-data") {
        return 403;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

At the network edge, enable emergency managed WAF rules both Cloudflare (including on its free tier) and Google Cloud Armor partnered with Wiz Research prior to disclosure to deploy stopgap signatures. Ensure origin servers cannot be reached directly around your CDN/WAF. For End-of-Life servers (PHP 5.x–7.3) that cannot be patched at all, follow CERT-EU’s directive: isolate them from the public internet behind a VPN or Zero Trust Network Access (ZTNA) gateway immediately.

Detection & Threat Hunting: How to Check If You Were Exploited (IOCs)

Because PHP2Shell executes inside the PHP engine below the application layer (and often before a single line of application PHP runs), application-level logs like WordPress activity plugins or Laravel’s laravel.log will typically show nothing.

Defenders must hunt across reverse proxy logs, PHP worker error logs, and OS process telemetry.

1. Network & HTTP Log Indicators

Look for these three high-signal anomalies in your NGINX, Apache, Envoy, or CDN logs:

  • Bursts of multipart/form-data requests paired with HTTP 500 errors: Repeated multipart requests (on POST or non-POST methods) from the same source IP or ASN that trigger 500 Internal Server Error or 502 Bad Gateway (worker crash) responses.
  • Abnormally large or malformed Set-Cookie: PHPSESSID= response headers: Under normal operation, a PHP session ID is a short alphanumeric string (typically 26 to 40 characters). In a CVE-2026-109618 memory disclosure attack, PHP URL-encodes leaked heap memory into PHPSESSID, producing unusually large Set-Cookie response headers or high response header byte counts.
  • Fatal Out-of-Memory errors at Unknown on line 0: Search your PHP error logs for memory exhaustion occurring during pre-script initialization.
bash
# 1. Hunt for PHP Out-of-Memory errors, especially during pre-script startup ("Unknown on line 0")
grep -REi "Allowed memory size of [0-9]+ bytes exhausted|Out of memory" /var/log/php* /var/log/apache2 /var/log/httpd /var/log/nginx 2>/dev/null

# 2. Hunt for unexplained PHP-FPM worker crashes (SIGSEGV / signal 11 or SIGABRT / signal 6)
grep -REi "exited on signal (11|6)|SIGSEGV|SIGABRT|child .* exited" /var/log/php* /var/log/syslog /var/log/messages 2>/dev/null

# 3. Search access logs for repeated HTTP 500/502 responses on POST/PUT/PATCH requests
awk '$9 ~ /^(500|502)$/ {print $1, $4, $6, $7, $9, $10}' /var/log/nginx/access.log | sort | uniq -c | sort -nr | head -n 30

2. Endpoint & Process Telemetry (Detecting Post-RCE Shells)

Monitor what your PHP worker processes spawn. A legitimate web application rarely needs php-fpm, php-cgi, httpd, apache2, frankenphp, or lsphp to execute /bin/sh, bash, curl, wget, python3, nc, or socat.

If your Linux servers do not run an eBPF-based EDR sensor, you can deploy Florian Roth’s lightweight process-watcher or add an auditd rule watching execve calls originating from your web server user (www-data, apache, or nginx):

bash
# Audit every command executed by the www-data user (UID 33 on Debian/Ubuntu)
sudo auditctl -a always,exit -F arch=b64 -S execve -F uid=33 -k php2shell_exec

# Review captured process executions in real time
sudo ausearch -k php2shell_exec -i

3. Incident Response Checklist If You Suspect Compromise

If you discover evidence of PHP2Shell exploitation or pre-patch memory disclosure:

  1. Isolate the host immediately from public and internal networks while preserving live memory and disk snapshots.
  2. Preserve web server, reverse proxy, and PHP-FPM logs before log rotation overwrites them.
  3. Rotate all secrets accessible to the PHP process: Because CVE-2026-109618 leaks live worker heap memory without leaving a web shell or touching the filesystem, assume that every database password, .env secret, cloud IAM credential, JWT signing key, API key, and user session token held in PHP memory during the exposure window has been compromised.
  4. Hunt for persistence: Inspect the web root for newly created or modified .php files, check /tmp and /dev/shm for staged binaries, and audit user crontabs (/var/spool/cron), /etc/crontab, systemd timers, and authorized_keys.

Real-World Impact: Active Exploitation Attempts and Precautionary Shutdowns

Even before the official patch landed at 14:00 UTC on October 21, threat actors were probing internet-facing PHP infrastructure:

  • Early Attack Traffic: Cloudflare CTO Dane Knecht confirmed on October 21 that Cloudflare was already “seeing early attacks emerging and updating mitigations as new vectors show up,” emphasizing that WAF rules are a temporary stopgap until administrators patch.
  • BambooHR Outage: HR and payroll platform BambooHR proactively took its services offline across the United States, Canada, and Ireland as a precaution to protect customer data, warning of temporary payroll disruptions while emergency patching took place.
  • Dutch Government & Critical Infrastructure Shutdowns: In the Netherlands, state broadcaster NOS reported that MijnOverheid, DigiD (the national digital identity system), the Dutch House of Representatives (Tweede Kamer) website, the National Cyber Security Centre (NCSC-NL), and multiple Dutch education platforms went offline preemptively to apply the fix.

The PHP2Shell Disclosure Timeline

Date (2026)Milestone
August 19, 2026Wiz Research discovers the first core PHP vulnerability using Wiz Atlas, Gemini 4 Argon, and GPT-5.6 Sol.
August 20, 2026Unauthenticated RCE is confirmed against Drupal (drupal:latest).
August 21, 2026Unauthenticated RCE is confirmed against WordPress (wordpress:latest).
August 24, 2026Wiz Research reports the vulnerabilities to the PHP security team (alongside research by Calif and OpenAI’s Codex Security team).
September 21, 2026PHP acknowledges the reports and begins engineering a comprehensive engine-level fix with Google DeepMind’s Gemini team assisting.
October 20, 2026An anonymous post on Hacker News leaks the existence of CVE-2026-109618 and CVE-2026-109619; watchTowr confirms the leak is real.
October 20, 19:33 UTCPHP publishes an emergency advance notice moving the release forward 24 hours from October 22 to October 21 at 14:00 UTC.
October 21, 14:00 UTCPHP releases 8.5.12, 8.4.27, 8.3.36, 8.2.35, and 7.4–8.1 source backports; full technical advisories go public.

The AI Inflection Point: How Gemini 4 Argon & GPT-5.6 Sol Unlocked a 20-Year-Old Bug

Why did four catastrophic memory-safety bugs sit in plain sight inside the open-source code powering 70% of the web for over a decade with Calif tracing parts of the bug lineage back to PHP security research from 2004 without being exploited until now?

The answer is complexity.

Before frontier AI models, turning an Out-of-Memory Use-After-Free in PHP’s request teardown path into a reliable, unauthenticated RCE exploit was at the absolute limit of human capability. Every PHP version, SAPI, compiler build, and target application (WordPress vs. Drupal vs. Joomla) alters the exact heap layout. A subtle shift in memory allocation order breaks the exploit chain, requiring weeks of tedious manual heap grooming, reverse engineering, and GDB debugging for each target. For twenty years, that sheer complexity acted as a natural defensive moat.

Frontier AI demolished that moat.

As we explored in our analysis of The New Mythos Era and Google Threat Intelligence Group’s 2026 AI-Era CVE Trends, autonomous code-reasoning models have fundamentally changed the economics of both vulnerability discovery and exploit development. Wiz Research combined Wiz Atlas, Gemini 4 Argon, and GPT-5.6 Sol with automated testing and debugging harnesses. Equipped with those tools:

  • A single researcher completed in one week what previously would have taken an elite vulnerability research team months.
  • Once the core engine primitives were identified, AI models automatically iterated against live containers, analyzed crash states, adjusted heap layouts, and adapted working pre-auth RCE exploits across WordPress, Drupal, and Joomla in a matter of hours.
  • On the defensive side, Google DeepMind’s Gemini team used Gemini 4 Argon alongside harnesses similar in philosophy to Google Mantis to hunt down sibling variants across the PHP codebase and validate that the upstream patch eradicated the flaw at its root.

Just as Heartbleed (2014) exposed the fragility of shared cryptographic libraries and Log4Shell (2021) exposed deep transitive dependencies, PHP2Shell (2026) marks the inflection point where “too complex to exploit in practice” is no longer a valid security assumption.

Conclusion: Patch Your PHP Runtime Now

Like React2Shell (CVE-2025-55182) in the JavaScript ecosystem, PHP2Shell (CVE-2026-109618 and CVE-2026-109619) is a drop-everything-and-patch event for every organization running PHP in production. Because the vulnerabilities sit in the PHP engine itself, no application-level clean code, WordPress plugin update, or single php.ini toggle can fully protect an unpatched server.

Inventory every PHP runtime across your cloud workloads, containers, Linux hosts, and third-party appliances today. Upgrade immediately to PHP 8.5.12, 8.4.27, 8.3.36, or 8.2.35 (or verified distribution backports), restart your php-fpm and Apache workers, audit your memory_limit settings for the new hard-limit behavior, and rotate any credentials that resided in internet-facing worker memory prior to patching.

To further enhance your cloud security and implement Zero Trust, contact me on LinkedIn Profile or [email protected].

FAQ

Frequently Asked Questions (FAQ)

What is PHP2Shell (CVE-2026-109618 and CVE-2026-109619)?

PHP2Shell is the collective name for two critical memory-safety vulnerabilities (CVE-2026-109618 and CVE-2026-109619, both rated CVSS 9.2) in the core PHP runtime engine. Disclosed on October 21, 2026, by Wiz Research, Calif, and OpenAI, the flaws allow unauthenticated remote attackers to execute arbitrary code (RCE) or read sensitive process memory (passwords, API keys, tokens) on nearly any PHP version from 5.4 through 8.5, independent of the application running on top of PHP.

Which PHP versions fix PHP2Shell?

The official patched releases are PHP 8.5.12, PHP 8.4.27, PHP 8.3.36, and PHP 8.2.35, shipped on October 21, 2026. For End-of-Life branches, the PHP security team also published official source backports for PHP 7.4, 8.0, and 8.1, and major Linux distributions (Debian, Ubuntu, RHEL, Alpine) have backported the fixes into their managed packages.

Does setting session.upload_progress.enabled=0 fix PHP2Shell?

No. Setting session.upload_progress.enabled=0 only blocks one confirmed session upload-progress attack path in CVE-2026-109619. It does not mitigate CVE-2026-109618, the fatal-error backtrace Use-After-Free, or the OPcache cross-worker type confusion bug. Both the PHP security advisory and PHP core developers confirm that upgrading the PHP runtime is the only complete fix.

Are WordPress, Drupal, Joomla, and Laravel affected by PHP2Shell?

Yes, if they run on an unpatched PHP version. Wiz Research demonstrated unauthenticated pre-auth RCE against the latest official container images of WordPress, Drupal, and Joomla. Updating the CMS or framework itself does not fix the vulnerability you must update the underlying PHP runtime (PHP-FPM, mod_php, CGI, FrankenPHP, or LiteSpeed) and restart all PHP workers.

Why is Apache mod_php at higher risk than PHP-FPM?

While both Apache mod_php and PHP-FPM are vulnerable and have demonstrated RCE paths, Apache mod_php is rated highest risk because a single unauthenticated exploit chain can trigger remote code execution during request setup before any application code runs. PHP-FPM shuts down a worker when certain early setup failures occur, though attackers can still exploit PHP-FPM via cross-request worker survival, shared OPcache type confusion, and Heartbleed-style memory disclosure.

How does the PHP2Shell Heartbleed-style memory leak work?

Under CVE-2026-109618, PHP parses RFC 1867 multipart requests during startup and stores a session ID pointer in PS(id). If an Out-of-Memory error aborts the request, PHP frees the request heap while leaving PS(id) dangling. A subsequent multipart request handled by the same worker reads that stale pointer and URL-encodes raw worker heap memory including other users’ passwords, tokens, and API keys into a Set-Cookie: PHPSESSID response header, even if the application never calls session_start().

How can I check if my server was exploited by PHP2Shell?

Because PHP2Shell triggers inside the PHP engine below the application layer, check web server and OS logs rather than application logs. Hunt for unusual multipart/form-data requests followed by Out-of-Memory errors or repeated HTTP 500 responses, abnormally large Set-Cookie: PHPSESSID response headers, unexplained PHP worker crashes (SIGSEGV/SIGABRT), and php-fpm or apache2 processes spawning shells (sh, bash, curl, wget).

Was PHP2Shell rated CVSS 10.0 or CVSS 9.2?

The official PHP security advisory rates both CVE-2026-109618 and CVE-2026-109619 at 9.2 on the CVSS v4.0 scale. The CVSS 10.0 figure circulated on October 20 came from an unofficial Hacker News leak prior to the official advisory.

Resources