Two days after PHP2Shell (CVE-2026-109618 and CVE-2026-109619) went public, two claims are going around: that the official PHP fix is incomplete, and that the bug is so hard to exploit that nobody needs to worry. Both are mostly wrong. The patch fixes the root cause, and the bug is very exploitable in 2026. The answer is the same as on day one: run a patched PHP version.

If you are a HEO Systems customer and want to know what we did on 21 October, read our incident report: PHP2Shell: What We Did and What It Means for You. In short, every website we host runs on patched PHP, and we found no signs of abuse on our servers.

Key Takeaways

  • PHP2Shell is two critical flaws in PHP itself, both rated CVSS v4.0 9.2, that allow unauthenticated remote code execution.
  • The fixed releases are PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP says updating is "the only complete mitigation".
  • The viral "incomplete fix" screenshots show other PHP bugs that need you to already be running your own PHP code. They are not PHP2Shell bypasses.
  • On 23 October PHP did announce one narrow follow-up issue in session upload progress (CVE-2026-115560). It needs an unusual configuration, and the fix comes with the next release.
  • Most public proof-of-concept exploits are fake or broken, but working exploits exist, and AI agents have made the hard part much faster.

What is PHP2Shell?

PHP2Shell is the name for two vulnerabilities in PHP's core memory and error handling, disclosed on 21 October 2026 in two official PHP security advisories:

  • CVE-2026-109618, "RCE via OOM corruption" (GHSA-w8hw-w9fx-j79w). PHP uses longjmp() to abort a request when it runs out of memory. If an allocation fails at the wrong moment, PHP "leaves the request memory in an invalid state".
  • CVE-2026-109619, "RCE via stale global state" (GHSA-6wmf-4rv5-p3rp). A PHP worker keeps global state, such as error, session and extension state, that "points to memory owned by one request". The next request can read that stale state before it is reset, causing a use-after-free.

Researchers at Calif found the bugs, and JFrog says Wiz and OpenAI reported related findings (JFrog Security Research).

What makes it serious is where it happens. The attack runs while PHP is still handling the incoming request, before WordPress, Laravel or any custom code is loaded. Your application's login, firewall plugin or security plugin never gets a chance to step in. PHP's advisories confirm remote code execution "over HTTP against mod_php with default PHP input and memory limits", and the session lifecycle path was "validated against mod_php and FPM".

watchTowr reports exploitation in the wild since 21 October through its honeypot network (watchTowr).

Is the PHP2Shell fix incomplete?

No. The official patch fixes the root cause of both CVEs. The "PHP is still vulnerable on the latest version" posts we have seen describe other bugs. There is one real follow-up from PHP itself, covered below, but it is narrow.

The screenshots that went viral show a PHP script being run locally that triggers a memory-error report (AddressSanitizer output). That is a memory bug, but it needs the attacker to already be running their own PHP code on the server. One security researcher who has been building PHP2Shell exploits in public made this point in a follow-up video. They showed a separate re-entrancy bug that still works on the newest PHP, and explained why it does not matter for most setups.

The reasoning is simple. If an attacker can already run arbitrary PHP on your server, they can call system('id') directly. They do not need a memory bug to do it. A browser bug is different, because every browser runs untrusted JavaScript from strangers all day. PHP does not work like that. The few places where this kind of bug matters are hosting setups that use "disabled functions" lists as their only isolation. A memory bug can sometimes get around those lists.

Several GitHub repositories mix these unrelated bugs, or deliberately weakened setups, with the PHP2Shell name. If you point an AI assistant at one and ask "is this real?", it will often say yes, because something in it is real. It just isn't PHP2Shell.

How the fix actually works

The original bug comes from how PHP handled hitting memory_limit. When an allocation went over the limit, PHP raised a fatal "Allowed memory size exhausted" error and jumped straight out of the code it was running (a "bailout", using longjmp). Cleanup code that was supposed to clear certain pointers never ran. Those pointers then referred to freed memory, which a second request could reuse. This is a classic use-after-free.

The patch removes the jump. The PHP 8.5.12 changelog lists it as "Avoid state corruption via bailout". JFrog describes the change this way: "OOM no longer aborts mid-operation." Running out of memory "becomes a soft error at the next VM safe point (or a hard _exit() past a higher threshold)", so "the cleanup always runs and the pointer is always cleared before the memory is freed" (JFrog).

In practice, the allocator now sets a "delayed out-of-memory" flag instead of jumping out. Functions such as the POST handler check that flag only after they have finished and tidied up. As defence in depth, long-lived state such as error backtraces, OPcache and session data is also reset at shutdown. This is a deep change to PHP's memory handling. It fixes the root cause, not a single exploit path.

The one real follow-up: session upload progress

On 23 October, PHP published an informational advisory on session upload progress. It describes a remaining case, CVE-2026-115560, that "can only occur under an unusual combination of configuration and application code". The application must set session.serialize_handler to php_binary or php_serialize in its configuration, then switch it to php with ini_set() before calling session_start().

PHP will publish the full advisory and fix with the next release. Until then it suggests setting session.upload_progress.enabled=0. This is a narrow edge case, not a bypass of the main patch, and most applications never switch serialize handlers at runtime.

Workarounds really are incomplete

The bigger "incomplete" story is about workarounds, not the patch. Before the release, people shared settings such as session.upload_progress.enabled=0 and memory_limit=-1. PHP's own advisories are clear: memory_limit=-1 "is not a complete mitigation", disabling upload progress "does not mitigate the other lifecycle paths", and "there is no complete generic configuration mitigation". JFrog reaches the same conclusion: "Each measure is partial on its own" (JFrog).

Is PHP2Shell too hard to exploit?

No. The claim that it is "too hard" mixes up two facts that are both true:

  1. Most public exploits do not work. There are thousands of PHP2Shell "PoCs" on GitHub. Many only succeed against a server that was made vulnerable on purpose. Some are malicious: JFrog found one with a hidden payload aimed at the person running it (JFrog). Do not run random exploit code from GitHub.
  2. Real exploits exist anyway. PHP's own advisory states that complete remote code execution "was validated over HTTP against mod_php with default PHP input and memory limits" (GHSA-w8hw-w9fx-j79w). JFrog says it reached "several working POC's", and TryHackMe reports remote code execution "against Apache with mod_php using default settings" (TryHackMe).

The researcher mentioned above described their own test in the same video. They set up an isolated lab with no SSH keys, so the agent could not peek at memory, and firewalled it to their own machines. They put a hand-edited flag in index.php as proof of success, and let AI agents work against the official php:8.5.4-apache Docker image. They got remote code execution in under two hours. They then showed the same exploit against a stock WordPress image.

Why "hard" means something different in 2026

PHP2Shell is still a use-after-free. Exploiting it needs careful heap grooming, a memory leak to defeat ASLR, and different offsets for each PHP build. Three years ago that work could take a skilled person days per target. When the sudo heap overflow (Baron Samedit) was disclosed in 2021 with full details, the first public exploit for a single build took about three days.

For PHP2Shell, the technical details were not even public yet, and working proofs of concept appeared within about 24 hours. The per-target work is exactly the kind of repetitive job an AI agent can grind through: one prompt, one Docker image, one set of offsets, repeated across the hundreds of official php:*-apache images. An exploit being hard to write by hand no longer tells you much about how soon attackers will have one.

What should you do?

HEO Systems customers: you do not need to do anything for PHP itself. All web hosting and managed WordPress sites run on patched PHP versions. Alternative PHP versions in the PHP Selector stay disabled until they are patched. The details are in our PHP2Shell incident report. We do recommend updating your WordPress or CMS plugins and themes, as you always should. Contact us on Discord if you need a PHP version other than 8.3.

If you run your own PHP servers (VPS, dedicated, Docker):

  • Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or newer, and restart every PHP worker (Apache, PHP-FPM, FrankenPHP). The downloads are linked from the official PHP release announcements.
  • Rebuild container images. A FROM php:8.x-apache base does not update itself.
  • PHP 8.1 and older get no official release. Use a distribution or LTS vendor package, PHP's minimal source backports (7.4, 8.0, 8.1), or upgrade (watchTowr). PHP 8.2 reaches end of life on 31 December 2026, so plan that upgrade now (TryHackMe).
  • If your application switches session.serialize_handler at runtime, set session.upload_progress.enabled=0 until the next PHP release.
  • Treat config workarounds as a stopgap only, never as a replacement for the patch.

Server software keeps getting serious bugs. Earlier this year we wrote about a similar case in nginx (CVE-2026-42945), and the advice was the same: patch quickly and restart the service.

Frequently Asked Questions

Is the latest PHP version still vulnerable to PHP2Shell?

No. PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 fix both CVE-2026-109618 and CVE-2026-109619. The viral "still vulnerable" posts show other memory bugs that require the attacker to already be running their own PHP code on the server. PHP has announced one narrow session upload-progress issue (CVE-2026-115560) that needs an unusual configuration and will be fixed in the next release.

Do the public PHP2Shell exploits work?

Most do not, and some are malware aimed at whoever runs them. Working exploits do exist, though: PHP itself confirmed remote code execution against mod_php with default settings, and several research teams have reproduced it.

Is my HEO Systems website affected?

No. We blocked the attack before the patch was out, installed the patched PHP on all servers when it was released on 21 October, and found no signs of abuse. See the incident report for the full timeline.

Sources: PHP advisory GHSA-w8hw-w9fx-j79w (CVE-2026-109618) · PHP advisory GHSA-6wmf-4rv5-p3rp (CVE-2026-109619) · php.net security advisory, 21 October 2026 · php.net session upload progress advisory, 23 October 2026 · PHP 8 ChangeLog · JFrog Security Research · watchTowr PHP2Shell FAQ · TryHackMe: PHP2Shell patch · Help Net Security