Tech7 min read

PHP patched php2shell, then a page claimed RCE still survives on 8.5.12

IkesanContents

TL;DR

What’s patched On October 21, 2026 PHP shipped 8.5.12, 8.4.27, 8.3.36, and 8.2.35, fixing two unauthenticated RCE flaws (CVE-2026-109618/109619, “php2shell”, CVSS 9.2). Exploitation attempts were seen in the wild the same day.
What’s claimed A self-published page appeared the same day claiming gaps still survive on the patched 8.5.12. None of it is filed with PHP, and the two claims labeled RCE are not in a form anyone else can reproduce.
What to do Update first. The “still survives” claim is low-confidence and is not a reason to hold off patching.


On October 21, 2026 PHP published advisories and fixed two unauthenticated remote code execution (RCE: an attacker running their own code on the server from the outside) flaws across 8.5.12, 8.4.27, 8.3.36, and 8.2.35.
The CVE IDs are CVE-2026-109618 and CVE-2026-109619, both rated 9.2 on CVSS v4.0 (an index scoring vulnerability severity from 0 to 10). The nickname is “php2shell”. watchTowr says it saw traffic attempting exploitation on release day through its honeypots (decoy servers that observe attacks) (watchTowr FAQ, Help Net Security).

Right after the fix, a self-published page (php2shell-zeros) appeared claiming that gaps still remain on the patched 8.5.12.
The page even ships proof-of-concept RCE code and attack scripts, but this article does not touch reproduction. It only checks which claims are confirmed and which are still unverified.

The two flaws the fix addressed

The advisories are the official GHSA-w8hw-w9fx-j79w and GHSA-6wmf-4rv5-p3rp, both published October 21. The official changelog dates 8.5.12 to October 22, so the announcement and advisories are from the 21st while the changelog’s build date is the 22nd (PHP changelog).

The two have different root causes, but both can reach unauthenticated RCE. Both are CVSS 9.2.

CVESummary
CVE-2026-109618PHP uses longjmp() to abort on out-of-memory. If an allocation fails while memory is reachable before it is fully initialized, invalid request memory is left behind, and shutdown then treats it as valid
CVE-2026-109619A use-after-free (UAF): stale per-worker (a resident process that handles requests) global state still points at memory from a finished request, and a later operation uses it before normal request initialization. Exploitation requires both a producer and a consumer

longjmp() is a C mechanism that jumps across the call stack back to an earlier point. CVE-2026-109619 has two triggers. The advisory calls the path through PHP 8.5’s fatal_error_backtraces (which stores a backtrace on a fatal error) its most strongly demonstrated case. The other runs through session upload progress (the feature that records how far an upload has gotten), which is enabled by default.

Here is how the fixed and the limited older series break down.

SeriesStatus
8.5 / 8.4 / 8.3 / 8.2Fixed in 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35
7.4 / 8.0 / 8.1Limited updates only
5.xNo official fix

watchTowr reports the scope as “all of PHP 5, 7, and 8”, but says itself that no vendor advisory confirms this wide range. Whether it works on a default configuration is not pinned down in primary sources either. Whether your environment is affected comes down to your PHP version and whether your host has applied the patch.

The “gaps still remain” claim from the same day

On release day, posts on social media said the patch was incomplete. Checking the primary sources, most of that came from a separate older bug, or from things still unverified mid-reproduction. The php2shell-zeros page above is one of these; the author (@acd421, stated to be agent-assisted work) lists four items.

The items differ in whether they are filed with PHP and how far they have been demonstrated. Only one is confirmed, a regression (a fix that introduces a new defect) added by the patch itself. The two claimed as RCE have no official filing and are not in a form anyone else can reproduce under the same conditions.

Author’s labelThe claimFiling statusWhat’s demonstrated
Zero 1 (session handling gaps)Unauthenticated RCE and session wipe remain on the patched 8.5.12Unfiled; held for coordinated disclosureAuthor’s own logs only; no third-party reproduction
Zero 2 (GC double-free regression)A bug the fix introduced can crash the serverThe underlying bug was filed the same day by someone else (evankford) as php-src #24488 / PR #24494A remote crash (DoS). The author states that on a stock build, promotion to RCE is structurally blocked
Zero 4 (use-after-free in unserialize)A use-after-free (UAF) occurs on the patched 8.5.12Unfiled; claimed as a first demonstrationReproduces only under ASAN (a debug build that detects memory faults). The author states the same input does not surface on a normal build
Zero 3 (analysis of what the patch does)No vulnerability claimed; an analysis of what the patch actually closedN/AAnalysis only

The one confirmed item, Zero 2’s regression, is a GC (garbage collection: the mechanism that automatically reclaims memory no longer in use) double-free of SimpleXML’s internal properties table, and it was filed with PHP proper by another researcher, evankford. But even by the author’s own analysis, on a stock build the impact stops at a crash and denial of service (DoS). Carrying that further to code execution is prevented by protections in ZendMM (PHP’s memory manager). It is not RCE.

The remaining Zero 1 and Zero 4 are unfiled, demonstrated only in the author’s own logs or a debug-only build. Zero 4 in particular reproduces only under an ASAN build and does not surface on a normal build. With self-published, agent-assisted, and unfiled all stacking up, for now these are claims awaiting reproduction rather than confirmed vulnerabilities. The author is also holding the disclosure decision as coordinated vulnerability disclosure (CVD: setting the timing in coordination with the people the report goes to).

What admins should do now

Prioritize the response to php2shell itself, which is confirmed. The “still remains” claim is low-confidence and is no reason to delay patching. The advisories state for both CVEs that updating is the only complete mitigation; the settings below are stopgaps for when you cannot update.

ActionDetail
Update the versionMove to one of 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35. On shared or managed hosting, confirm the host has applied the patch
Older series7.4 / 8.0 / 8.1 have limited updates and 5.x has no fix. If you are on those, consider migration or mitigation with a WAF (a layer in front of a web app that blocks malicious requests)

The stopgaps for when you cannot update are listed per CVE in the official advisories. None is complete.

CVEStopgap when you cannot update (official advisory)
CVE-2026-109618Administratively enforcing memory_limit=-1 (unlimited) is the primary configuration mitigation. Also keep post_max_size conservative and limit request size and multipart at the front end. Do not use RLIMIT_AS or RLIMIT_DATA, which make mmap() fail
CVE-2026-109619On PHP 8.5 set fatal_error_backtraces=0; for the session path set session.upload_progress.enabled=0, administratively, and restart every worker. Each setting closes only one of the two triggers

Setting memory_limit to unlimited for CVE-2026-109618 is counterintuitive, but since the vulnerability starts from the abort on out-of-memory, the official guidance makes avoiding that abort the primary measure.

If you run a CMS such as WordPress, what’s vulnerable is not the application but the PHP underneath it, so check PHP itself (usually a version switch in your hosting control panel) rather than updating plugins or themes (Codeable’s write-up).