php2shell.in
CRITICAL • PATCHED 21 OCT 2026

PHP2Shell

Two critical vulnerabilities in the PHP engine itself that let an unauthenticated attacker run code on your web server over plain HTTP — and even read its memory. Your application can be fully up to date and still be exposed.

CVE-2026-109618 — RCE via memory exhaustion
CVE-2026-109619 — RCE via fatal errors
CVSS 4.0: 9.2 Critical (both)

⚠ If you run PHP, do this now

Upgrade to 8.2.35, 8.3.36, 8.4.27 or 8.5.12 — then restart every PHP worker (Apache, PHP-FPM). Updating WordPress, Laravel, Drupal or plugins does not fix this. Check changelogs if you use distro packages, which may backport the fix under older version numbers.

01What is PHP2Shell?

PHP2Shell is the nickname researchers gave to an exploit chain built on two separate memory-safety bugs in the PHP interpreter — not in WordPress, Laravel, or any plugin. Because the vulnerable code runs while PHP is reading the request, before your application gets a say, even a fully patched application on a vulnerable PHP build can be taken over.

Both flaws are classified as CWE-824: Access of Uninitialized Pointer. The shared pattern, in one sentence: PHP can leave internal state corrupted when a request ends abnormally, and a later request — or the shutdown path of the same request — then trusts that state.

The bugs were reported by researchers at Calif, Wiz, OpenAI’s Codex security team (and Quarkslab on one of them), working with the PHP security team — found with AI assistance, and disclosed as GitHub advisories GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp.

Timeline

Code paths introduced
The vulnerable code paths date back to PHP 5.4.0 (2012) — a ~14-year-old bug.
Pre-disclosure
Exploit attempts observed in the wild before the public announcement; details leaked a day early and a PoC video was briefly posted, then removed.
21 October 2026
PHP ships emergency releases: 8.2.35, 8.3.36, 8.4.27, 8.5.12 — plus source backports for the EOL 7.4, 8.0 and 8.1 branches.

02The two CVEs

CVE-2026-109618
CVSS 9.2 • Critical

RCE via memory exhaustion

PHP uses longjmp() to abort a request when it hits an out-of-memory error. Some execution contexts don’t account for that interruption, leaving request memory uninitialized. Later cleanup reads or branches on that memory → remote code execution.

Also enables remote memory disclosure: the session upload-progress handler can return chunks of freed server memory inside the PHPSESSID response cookie — a Heartbleed-style leak that can expose DB passwords, session tokens, API keys, even TLS private keys.

CVE-2026-109619
CVSS 9.2 • Critical

RCE via fatal errors

PHP also uses longjmp() to abort on fatal errors. Some contexts leave global state pointing at memory that gets freed at the end of the request. A subsequent request reads or branches on that invalid state → use-after-free → remote code execution.

Includes a fatal-error backtrace generation use-after-free and an OPcache type-confusion primitive.

How the attack works (simplified)

  1. The trigger runs before your code. Three of the five demonstrated techniques abuse PHP’s session upload-progress feature, which parses multipart request bodies before the application executes. An endpoint that just echoes “OK” can be affected.
  2. Memory exhaustion at the wrong moment. A crafted multipart request forces an OOM bailout mid-processing — after PHP published a pointer or cache slot, but before cleanup bookkeeping ran.
  3. Stale state survives. In worker-based SAPIs (e.g. Apache prefork) one process serves many requests. The next request landing on the same worker finds a pointer to already-freed memory.
  4. Heap shaping → code execution. The attacker’s follow-up request places carefully shaped data into that freed space. Get the timing right and the worker executes attacker code as the PHP worker user — no login, no user interaction.

Demonstrated primitives beyond RCE: ~67 KB of process-memory disclosure via the PHPSESSID cookie, arbitrary file read via a stale OPcache class-cache slot redirecting a file operation, session decoder use-after-free, and worker crashes. Note: attack complexity is rated high — triggering the bug is easier than weaponizing it into reliable RCE, but it has been demonstrated, including against stock WordPress/Drupal/Joomla containers.

03Am I affected?

Check your PHP version on every web server (and don’t forget embedded copies — sidecars, workers, appliances need separate inventory):

# check the version
php -v

# example of a VULNERABLE build
PHP 8.3.35 (cli) ...   # < 8.3.36 → vulnerable

# example of a FIXED build
PHP 8.3.36 (cli) ...   # patched
QuestionAnswer
Which PHP versions?Believed affected back to 5.4.0 (2012). Fixed in 8.5.12, 8.4.27, 8.3.36, 8.2.35; source backports published for 7.4 / 8.0 / 8.1. Distro packages may carry the fix under older numbers — check the changelog for the CVE IDs.
Which SAPIs?Apache mod_php is the easiest target and highest risk; also PHP-FPM, php-cgi, FrankenPHP, LSAPI, Windows PHP.
Does updating WordPress / plugins fix it?No. This is in the PHP runtime. CMS and framework updates are irrelevant to this bug.
Does the app need sessions/uploads?Not necessarily — the upload-progress trigger runs before application code, even if the app never calls session_start().
What does the attacker get?Code execution as the web worker user (not root automatically) — enough to read configs/DB creds, drop webshells, and pivot. Plus potential memory disclosure of secrets and keys.

04Fix it

The real fix (do this)

  1. Upgrade PHP to 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35 (or apply your distro’s backported package).
  2. Restart every PHP worker — Apache, PHP-FPM, FrankenPHP, anything long-running. The patch only takes effect after restart.
  3. Investigate whether the server was touched before you patched (see below) — assume memory disclosure is possible, so consider rotating DB passwords, API keys, and TLS certificates on exposed hosts.

Can’t patch today? Temporary exposure reduction

These are not complete workarounds — they only remove the demonstrated triggers. Patch as soon as possible.

; in php.ini — temporary mitigation only, NOT a fix
session.upload_progress.enabled = 0
opcache.enable = 0

Signs you may already be compromised

05FAQ

Is PHP2Shell a WordPress bug?
No. It lives in the PHP interpreter. Every PHP application — WordPress, Drupal, Joomla, Laravel, custom code — is exposed if the underlying PHP build is vulnerable.
Does the attacker need an account?
No. Exploitation is unauthenticated and needs no user interaction — a single crafted HTTP request can trigger the primitives.
Why “Heartbleed of PHP”?
Because CVE-2026-109618 can leak ~67 KB of live server memory per request through a response cookie, potentially including secrets and private keys — the same class of failure that made Heartbleed infamous.
Why did it take 14 years to find?
The bugs sit in exceptional code paths (OOM bailouts, fatal-error handling) that are hard to reach reliably, and turning the memory corruption into working RCE needs precise heap shaping. AI-assisted research made that practical in 2026.
I’m on PHP 7.4 / 8.0 / 8.1 — am I out of luck?
Those branches are end-of-life, but the PHP team published source backports. Otherwise, migrate to a supported branch or rely on your distro’s backported package — and apply the temporary mitigations meanwhile.

06Sources

CVE-2026-109618 • CVE-2026-109619 • CWE-824 • CVSS v4.0 9.2 (Critical). This page is educational and defensive — it explains the vulnerability and how to fix it. Last updated 22 Oct 2026.