devploit/php2shell
PHP2Shell is a research toolkit by devploit that reproduces a pre-auth remote code execution issue in PHP, tracked as CVE-2026-109618 and CVE-2026-109619, affecting the Apache mod_php and PHP-FPM SAPIs. The repository includes version-matched profiles for many PHP 7.4 through 8.5 builds, reproducible Docker and nginx test labs, a technical write-up of the vulnerability, and mitigation and detection recommendations for defenders.
What it is
devploit/php2shell is a research toolkit for CVE-2026-109618 and CVE-2026-109619, a pre-auth RCE in PHP's session.upload_progress handling. It wraps the public exploit by 9bie with a version-aware dispatcher, per-build profiles and disposable labs. The README says it is for authorized testing only. It also warns that running the chain is disruptive: it sends large bodies, triggers out-of-memory conditions before request startup and kills Apache children. The repo credits Wiz Research with the discovery and does not claim the CVE as its own.
How it works
The upload-progress callback runs before request startup (pre-RINIT), so before any application script.
- Apache mod_php: a multipart request forces an out-of-memory bailout after the session state is built. The next request reuses the stale
PS(id)and returns aSet-Cookiecontaining heap pointers (stage 1). The same primitive then leaks a libphp pointer (stage 2). Stage 3 lands a forged HashTable and reference on the stale state, so thezval_ptr_dtorpath callszif_system. - PHP-FPM behind nginx: an OOM kills the worker, so the Apache carrier does not apply. The chain instead leaves
BG(unserialize)dangling. The next request reclaims the 8216-byte struct with a 4 MB body, and a forged session variable makes session shutdown callzif_system.
Preconditions / Affected
Fixed releases are 8.4.27 and 8.5.12 for those branches, per the repo's catalog/vulnerable.json. Fixes for other branches are listed there but not in the page text, and the repo says to check them against current PHP advisories.
The shipped Apache calibration needs all of the following:
- prefork with mod_php and one worker (multiple workers need
--pin-workers) display_errors=Onandmemory_limit=8Msession.upload_progress.enabled=On,session.use_cookies=1,session.use_strict_mode=0post_max_sizeat leastmemory_limitplus 12M. The stock 8M default blocks the chain, because PHP rejects the oversized body before parsing.
The FPM chain in its stock shape needs:
- nginx with
client_max_body_sizeof at least 5m (stock is 1m) memory_limit=128M,pm=dynamic,post_max_size=8M- an application that calls
session_start(), stores a reference, reflects a session value, and either decodes attacker data withsession_decode()or accumulates session data
Verified exploitation, as reported by the repo:
- 56 profiles (48 Apache, 8 FPM), 30 with verified RCE.
- Apache RCE is confirmed on selected PHP 8.4.x and 8.5.x builds.
- FPM RCE is confirmed over HTTP on 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.
- 8.2, 8.1, 7.4 and 8.0 Apache images were tested and showed no working leak. The repo says "no" means not verified, not necessarily safe.
- On 2026-10-30 the maintainer independently reproduced the command proof for the stage-3 PR profiles (8.4.10, 8.4.11, 8.4.19, 8.4.20, 8.4.25 amd64, 8.5.0 to 8.5.10 amd64, 8.5.11 aarch64). The FPM and deb13/apxs2 profiles are contributor-reported only.
What to do
The repo's defensive guidance, in order of strength:
- Patch to a fixed release (8.4.27, 8.5.12, or the fixed release for the branch in use).
- Turn off the callback this chain needs, unless a specific endpoint requires it:
session.upload_progress.enabled=Off- Detect: multipart requests with about 1000 fields, very large bodies, repeated OOM or 500 responses, Apache child crashes, and
zend_mm_heap corruptedlog lines. Rate-limit large multipart bodies at the edge. - Run PHP as an unprivileged user with a read-only document root and no shell access.
- Avoid sharing session storage across trust boundaries.
display_errors=Off, a larger memory_limit and a read-only webroot only raise the cost. The repo says they are not fixes.
Caveats
display_errors=Offblocks the shipped stage-1 leak, but the repo says an OOM-in-cookie primitive is reproducible in research. The README lists that configuration as an open item, so it should not be treated as safe.- Profiles are tied to a specific libphp build. Distribution, architecture and compile-time prefix all shift the heap, so the lab results do not transfer directly to production hosts.
- A remote command is limited to 14 bytes, and remote proof depends on a writable, served webroot.
- HTTPS transport is unverified. Stage 1 did not reproduce over TLS in the repo's tests.
- The Apache labs use one worker and 8M memory. The page gives no results against hardened multi-worker production setups.
- The upstream exploit has no license, so the repo does not vendor it. A bootstrap script fetches it at a pinned commit (4586f5c).
Organisations named here
- Calif
- PHP Foundation
- 9bie
- Karasawa2025
- Wiz Research
- WoYinDao
CVEs named here
- CVE-2026-109618
- CVE-2026-109619
Technologies named here
- php2shell
- PHP 8.4.26
- Apache HTTP Server
- PHP-FPM
- nginx
- PHP
- Apache
- Docker
- Python
- bootstrap_upstream.py
- php2shell_assess.py
- php2shell_auto.py
- php2shell_calibrate.py
- php2shell_fpm_labs.py
- php2shell_fpm_matrix.py
- php2shell_fpm_offsets.c
- php2shell_fpm_profile.py
- php2shell_fpm.py
- php2shell_fpm_versions.py
- php2shell_inventory.py
- php2shell_labs.py
- php2shell_matrix.py
- php2shell_offsets.py
- php2shell_paths.py
- php2shell_rce.py
- php2shell_ui.py
- php2shell_upstream.py
- php2shell_vessel.py
- PHP 7.2.34 (FPM, plant only)
- PHP 7.4.33 (amd64, aarch64, FPM)
- PHP 8.0.30 (amd64, aarch64, FPM)
- PHP 8.1.33 (FPM)
- PHP 8.1.34 (amd64 bullseye, aarch64)
- PHP 8.2.0 (aarch64)
- PHP 8.2.28 (amd64)
- PHP 8.2.34 (amd64, aarch64, FPM)
- PHP 8.3.0 (aarch64)
- PHP 8.3.20 (amd64)
- PHP 8.3.33 mod_php (WordPress)
- PHP 8.3.35 (amd64, aarch64, FPM)
- PHP 8.4.0 (FPM)
- PHP 8.4.10 (amd64)
- PHP 8.4.11 (amd64)
- PHP 8.4.13, 8.4.8 (amd64)
- PHP 8.4.14-8.4.18, 8.4.12, 8.4.7, 8.4.6 (amd64)
- PHP 8.4.19 (amd64)
- PHP 8.4.2 (amd64)
- PHP 8.4.20 (amd64)
- PHP 8.4.25 (aarch64, amd64)
- PHP 8.4.5 (amd64)
- PHP 8.5.0 (amd64)
- PHP 8.5.10 (aarch64, amd64)
- PHP 8.5.11 (aarch64, amd64)
- PHP 8.5.1-8.5.9 (amd64)
- PHP 8.5.5 (amd64)
- WordPress 8.3.33
Techniques named here
- Exposure of Sensitive Information to an Unauthorized Actor
- Use-after-free
- Worker pinning
- Heap grooming / fake HashTable carrier
- Heap/memory out-of-memory (OOM) induced use-after-free
- Pre-auth remote code execution via session.upload_progress
- Request fan-out across pool workers
- Session file poisoning
Concepts named here
- Configuration-dependent exploitability
- Honest negative reporting
- Oracle vs no-oracle exploitation
- Stage 1/2/3 exploit chain structure
- Verification status tiers (independently confirmed vs contributor-reported)
- Version-aware exploitation profiles
Related in Offensive Security