By November 1, 859 public repositories claimed to target CVE-2026-109618, CVE-2026-109619 or the related CVE-2026-115560. About a quarter contain exploit code. That code targets several different deployments: Apache mod_php, PHP-FPM with specific application behavior, and applications with separate bugs. The confirmed compromises we reviewed haven't been tied to a public repo.

Don't wait for a working public exploit to act on an exposed PHP service. The limitations of these repos tell us little about the code an attacker may already have.

We pulled Mallory's repository analyses and exploitation records for the three CVEs on November 1. The analyzer reads each repository's code and records what it does, regardless of the README. We didn't execute the code. For remediation, see our PHP2Shell rapid-response post.

Nearly half the repos are scanners or checkers

Nearly half the repos are version checkers, exposure scanners or detection rules. Another 139 are mitigation scripts, unofficial backports for end-of-life PHP or research notes. 218 contain code that tries to exploit something.

PHP2Shell repos by what the code does

859 public repos across CVE-2026-109618, CVE-2026-109619 and CVE-2026-115560, each counted once

  • Scanner or checker
  • Exploit code
  • Mitigation or research
  • README only
  • Not analyzed
  • Misrepresented
Scanner or checker
407 (Scanner or checker)
Exploit code
218 (Exploit code)
Mitigation or research
139 (Mitigation or research)
README only
48 (README only)
Not analyzed
40 (Not analyzed)
Misrepresented
7 (Misrepresented)

Source: Mallory exploit analysis, November 1, 2026. The analyzer reads repository code; it does not run it.

What these exploits actually target

Start with how PHP runs. A public HTTP endpoint backed by Apache mod_php, an nginx site backed by PHP-FPM, and an exposed FastCGI listener are different targets. The application's behavior and the exact PHP binary matter too. A matching version string isn't enough.

PHP's OOM advisory explains the first distinction. Apache mod_php runs request cleanup even when startup fails. That lets a request reach the vulnerable path before application code runs, including application authentication. A PHP page doesn't need an upload feature or a call to session_start(); the request needs to reach PHP's parser. FPM kills a worker whose startup fails, so that same sequence doesn't carry over.

PHP-FPM is still affected. PHP's stale-state advisory confirms a session path that begins during application execution, after startup. A later request to the same worker consumes the stale state. That path needs a suitable application operation and can work with a normal dynamic worker pool.

We checked source and configuration for the examples below. These are concrete target requirements, not a count of working exploits. Reported successes belong to the repository authors; we haven't reproduced them.

Selected public implementations, source-checked November 2. Each source link identifies the reviewed commit.
TargetAccess and prerequisitesResult and source
Apache mod_php: Linux x86-64, PHP 8.4.26 or 8.5.11HTTP to a PHP handler. This implementation requires Apache prefork with one persistent worker, upload progress enabled, displayed errors, a reachable memory-exhaustion condition, and matching binary offsets. Its lab uses a 16M PHP memory limit.Author reports HTTP-only command execution as the PHP worker. Its PHP 8.3.35 profile is leak-only; other versions and architectures need separate calibration. alvarodh5 source
nginx + PHP-FPM: Debian-style Linux amd64, PHP 8.4.26 exampleHTTP access to specific application session operations, described below. Upload progress, file-backed sessions and matching binary profiles. The default-mode lab uses a 128M limit and five dynamic workers; its amplifier needs roughly 5 MB request bodies accepted by nginx.Author reports HTTP-only command execution, followed by worker termination. Application access requirements still apply. A second mode uses separate builder and consumer pools sharing sessions. VABISMO source
nginx + PHP-FPM 8.4.26: crash reproductionOne FPM worker, 32M PHP memory limit, a preloaded gadget and a large session planted through local Docker access before the HTTP requests.The README reports a worker crash, usually HTTP 502. It explicitly leaves FPM command execution unproven. fksegundo source
PHP-FPM lab builds, including 8.4.26: debugger-assisted chainA purpose-built PHP page calls parse_str() and supplies a shutdown callback. Local Docker/GDB access measures live addresses. Build, architecture, memory settings and worker layout must match the selected sample.A lab command-execution design with local calibration. It doesn't establish an HTTP-only chain against an existing application; public experiment receipts are absent. lynolz163 source
PHP built-in HTTP server: Linux amd64, Alpine PHP 8.4.26The Workshop-PHP2Shell image is tagged php:8.4.26-fpm-alpine3.23, but launches php -S behind nginx with four CLI server workers. The client is calibrated to that binary and lab.The workshop documents command execution against the development server. The FPM image tag doesn't establish PHP-FPM coverage. Workshop Dockerfile
Directly reachable PHP-FPM FastCGI listenerDirect FastCGI access in addition to HTTP, a poisoned session readable by the worker, a usable script path and acceptance of a PHP_VALUE override. An ordinary nginx HTTP endpoint alone doesn't provide this access.Attempts session-file inclusion through FastCGI. This route doesn't implement the PHP2Shell memory-corruption chain; an exact supported binary range is not established. syrex1013 client
PHP application with an existing local-file-inclusion flawHTTP multipart processing with upload progress enabled, usable file-backed sessions, and a separate include/require flaw that can execute the poisoned session file. The session must persist until inclusion.Application-level session poisoning plus LFI. The PHP version alone doesn't supply the required application flaw; this is separate from memory-corruption RCE. syrex1013 client
Application serializer mismatch: PHP 8.5.12 mod_php labThe application changes session.serialize_handler from php_binary or php_serialize to php before session_start(). Upload progress and shared sessions are required. This example supplies a file-writing gadget and a PHP-executable destination.Author reports object injection and command execution for CVE-2026-115560. The lab uses a release already patched for the two earlier memory-corruption CVEs. B63 source
PHP-FPM 8.4.26 with a deliberately unsafe callbackThe Dockerfile sets unserialize_callback_func=system and pre-populates a serialized session. Both conditions must already exist when the HTTP trigger arrives.Command execution through the supplied configuration and session data. This example doesn't demonstrate default-FPM memory-corruption RCE. ha1c9on Dockerfile

The FPM application requirements are the deciding detail

The FPM HTTP chain in the table needs an application that starts sessions, stores references in them, reflects session values, and lets attacker-controlled data reach a session-decoding or accumulation operation. It also expects file-backed sessions using the php serializer and an accepted session ID that remains usable across requests. The lab supplies those operations. Whether an existing application exposes them, and whether they require a login, needs its own review.

Its verification manifest reports HTTP RCE on specific amd64 builds of 7.4.33, 8.0.30, 8.1.33, 8.2.34, 8.3.35, 8.4.0, 8.4.25 and 8.4.26. Those are author-reported results on calibrated builds. They don't establish coverage of every distribution carrying those version numbers, ARM64, or PHP 8.5. The client also has local diagnostic modes, which we kept separate from its HTTP-only mode.

Lab settings aren't universal requirements

Several mod_php examples use one worker, a small memory limit and displayed errors. Other public implementations report different results: RuxaXa's lab uses PHP 8.4.26 with php.ini-production, and rayaar reports multi-worker mod_php success while still requiring displayed errors and disabled output buffering. A separate PHP 7.4.33 example has its own binary calibration. We can't infer safety from worker count, production INI settings or an older PHP branch.

Docker access also means different things in different repos. Reading a proof file from a container can be a convenience after an HTTP exploit. Using a debugger to discover worker addresses, or planting the session that the attack needs, is an additional access requirement. We checked which role it plays before describing a chain as remote.

WordPress or Laravel in a repo name doesn't identify the vulnerable component. For a mod_php runtime chain, the target is the PHP worker beneath the application. For an LFI or serializer-mismatch chain, the application has to supply the extra behavior. PHP's CVE-2026-115560 notice specifically requires a serializer change before session startup with upload progress enabled. Its scope is separate from the two memory-corruption CVEs.

We also found crash probes, incomplete chains and wrappers around missing code among the exploit-classified repos. A worker crash, a version match or a successful upload-progress write doesn't establish command execution. Where the implementation doesn't establish a runtime or build, its target remains unknown.

Most of the code arrived within 72 hours

The CVE IDs leaked at about 15:00 UTC on October 20. The first exploit repo appeared at 19:16 UTC that evening. 87 repos existed before PHP published its advisories at 13:34 UTC the next day, before authors could refer to PHP's description of the bugs.

672 repos (78%) were published from October 21 to 23. Output fell to a trickle after that. Neither the CISA KEV listing on October 26 nor Unit 42's confirmation on October 29 brought a second wave of public code.

New PHP2Shell repos per day

By what the code does. Hover a day for the breakdown.

  • Scanner or checker
  • Exploit code
  • Mitigation or research
  • README only
  • Not analyzed
  • Misrepresented
0100200300PHP advisoryKEV listingUnit 42112572831324437361915111085Oct 18Oct 20Oct 22Oct 24Oct 26Oct 28Oct 30Nov 1
Daily counts
New PHP2Shell repos per day
DateScanner or checkerExploit codeMitigation or researchREADME onlyNot analyzedMisrepresentedTotal
Oct 181000001
Oct 190000000
Oct 200100001
Oct 21107774713112257
Oct 2216547471491283
Oct 23633817590132
Oct 241515751144
Oct 25166742237
Oct 261614411036
Oct 2776213019
Oct 2835402115
Oct 2936011011
Oct 3052030010
Oct 314040008
Nov 12101105

Source: Mallory exploit analysis, November 1, 2026. Date is the repository's creation time in UTC. One checker carries an October 18 creation date and was likely repurposed after the leak.

"Weaponized" describes packaging, not reliability

Our classification labels 176 exploit repos operational and 4 weaponized, based on what the code is built to do. Three of the four weaponized repos ship the same php_up_framework.py, posted under different names within 11 hours on October 21. Two appeared before PHP's advisory. The label reflects how the code is packaged. It doesn't establish whether the exploit works.

Published (UTC)RepositoryCode
Oct 21, 03:06Zer061/CVE-2026-109618php_up_framework.py
Oct 21, 07:40cereZ23/php-up-2026php_up_framework.py
Oct 21, 14:05charindithjaindu/CVE-2026-109618php_up_framework.py
Oct 30, 07:23ArchonXDeadLocksecurity/ArchonX-PHP2ShellSeparate four-request chain

Public code and confirmed exploitation developed separately

VulnCheck and Trail of Bits each reported building a reliable private exploit. Neither has published it. The honeypot successes used single-worker mod_php setups favourable to the attacker. Wiz had found no public PoC that worked end to end against an arbitrary target as of October 27.

DatePublic codeWhat was confirmed
Oct 17NoneAmazon's MadPot honeypots log an attempt four days before disclosure; whether it would have worked is unknown
Oct 20CVE IDs leak; first exploit repo at 19:16 UTCA research firm's demonstration video leaks
Oct 21257 repos, 77 of them exploit codePHP publishes advisories at 13:34 UTC. Cloudflare, Imperva and watchTowr report attempts; none confirmed successful
Oct 22283 repos, the peak; 165 are scannersVulnCheck has a private weaponized exploit. Sophos withdraws its compromise claim
Oct 2415 exploit reposCode execution confirmed on honeypots. Trail of Bits calls its private exploit "production-grade". Adel Karimi records 35 shell executions on three single-worker mod_php honeypots
Oct 2614 exploit reposCompromise confirmed. CISA adds both CVEs to KEV. Dream Research reports 25 servers rooted by chaining PHP2Shell with Fragnesia
Oct 276 exploit reposWiz sees attempts but no successful exploitation in its telemetry, and no public PoC that works end to end
Oct 28 to 2911 exploit reposCompromise verified. Previdian confirms RCE on four favourable honeypots. Unit 42 verifies the attacker's tooling and PAN-OS management-interface exploitation

Sources: Amazon, Adel Karimi, Dream Research, Previdian, Unit 42. Public-code counts from Mallory exploit analysis.

Exploitation reporting came in two waves

We tracked 290 distinct reports from 158 sources. Coverage peaked on disclosure day and rose again with the KEV listing and the Dream Research report on October 26. Several reports can cover the same incident, so these counts measure coverage.

Distinct exploitation reports per day

Reports of PHP2Shell exploitation, each article counted once

0204060PHP advisoryKEV listingUnit 42260502569402829161722Oct 20Oct 22Oct 24Oct 26Oct 28Oct 30Nov 1
Daily counts
Distinct exploitation reports per day
DateReports
Oct 202
Oct 2160
Oct 2250
Oct 2325
Oct 246
Oct 259
Oct 2640
Oct 2728
Oct 2829
Oct 2916
Oct 3017
Oct 312
Nov 12

Source: Mallory exploitation records, November 1, 2026. Date is the activity start date extracted from each report. One October 17 report and three reports with misread dates fall outside the chart.

Who reported PHP2Shell exploitation

290 distinct reports by source type

News media
151
Social posts
49
Vendors, researchers
48
CERTs, government
41
Honeypot telemetry
1

Source: Mallory exploitation records, November 1, 2026. Shadowserver's honeypots logged 98 unique source IPs a day attempting CVE-2026-109618 on October 23 and 24.

CVE-2026-115560 is quieter. 42 repos reference it, nearly all alongside the two main CVEs. Its only exploitation record is Italy's ACN advisory for IceWarp, which is a patch notice rather than an attack report. It has no CVSS or EPSS score and isn't in KEV.

Some repos misrepresent what they do

We found seven PHP2Shell repos whose code contradicts their README. One ships a web shell while claiming to contain no payloads. Read any public PHP2Shell repo before running it, and never run one on a machine you care about.

  • hoed/php2shell: Ships a working PHP web shell and reverse-shell generator, while the README says it contains no payloads or reverse shells.
  • delvin-45/php2shell-CVE-2026-109618-CVE-2026-109619-PoC: A Docker lab with a web shell already installed. The "exploit" runs commands through the shell it planted.
  • 0x1c1101/CVE-2026-109618-PoC: The README admits it is fake. The Python file is mostly a copy of the standard library's http.client.
  • IamLucif3r/CVE-2026-109618-exploit: A Go tool with synthetic heap-spray records and a simulated lab. The exploit chain is incomplete.
  • cyberkiddle/CVE-2026-109618: Sends 5,000 nested form fields and a 35 MiB string: an allocation stress test with unsupported RCE claims.
  • l3tchupkt/php2shell and wakemeiflose/php2shell: Session poisoning that needs an existing file-inclusion bug in the application, presented as a PHP2Shell exploit.

What this means for defenders

  • Identify the PHP process behind each exposed endpoint: mod_php, FPM or another runtime. Record its package/build, architecture, upstream access controls and application session behavior. Compare those details with the relevant chain, and check vendor backports rather than relying on a version banner.
  • Prioritize exposed appliances. PAN-OS is where compromise was confirmed. Take management interfaces off the internet and apply the vendor fix.
  • Keep the upload-progress mitigation. session.upload_progress.enabled=0, applied before request parsing with workers restarted, blocks these upload-progress session paths and mitigates CVE-2026-115560. It does not cover every stale-state path, including PHP 8.5 fatal backtraces; follow the PHP advisory for the remaining conditions.
  • Check hosts that were exposed before patching for unexpected web-server child processes, new files in web roots and PHP worker crashes.

A failed public PoC is a poor reason to leave an exposed system unpatched.

- jcran