How should this version be classified?
PHP2SHELL
Two memory-safety bugs in the PHP interpreter's request lifecycle. Both let an unauthenticated attacker reach remote code execution with the web worker's privileges — the out-of-memory path (…618) before your application code even runs, and the stale-state path (…619) by reusing a worker across requests.
mod_php is the highest-risk configuration because the fault is reachable before application code runs. Patch out of your normal cycle.
Are you affected?
Enter the exact PHP version on the target. Logic runs entirely in your browser.
How each bug works
Both are classic memory-safety faults, reached through ordinary request handling. The mechanism below is conceptual — enough to understand reachability and impact, not a recipe.
- Class
- Memory corruption (heap)
- Trigger
- Allocation failure while per-request data is only partly initialized
- Attack vector
- Network, unauthenticated. Crafted multipart requests can exhaust memory while appearing within configured limits.
- Impact
- RCE as the web worker; confirmed from PHP 5.4.0 onward
- Highest risk
mod_php— fault reachable before app code
RLIMIT_AS / RLIMIT_DATA can actually trigger the vulnerable path. Container and cgroup caps help availability but are not a complete fix.- Class
- Use-after-free (cross-request)
- Trigger
- Leftover global state references memory freed at the end of an earlier request
- Confirmed paths
- Session upload-progress (on by default); fatal-error backtraces (PHP 8.5)
- Attack vector
- Network, unauthenticated. Worker reuse + an interrupted cleanup (fatal error or timeout).
- Impact
- RCE as the web worker; memory disclosure also confirmed
- Affected models
- Both
mod_phpand PHP-FPM
error_reporting, display_errors, @) does not stop stale-state access. Absent log entries do not prove an installation is safe.Public analysis maps the two CVEs to five concrete chains — one OOM path (…618) and four stale-state paths (…619). Each has a different precondition and runtime surface.
| Chain | CVE | Vector | Pre-auth | Precondition | SAPI |
|---|---|---|---|---|---|
| A | …619 | Session injection + LFI | yes | Application has an LFI sink | all |
| B | …619 | var_destroy UAF → handler overwrite | no | Application calls unserialize() | all |
| C | …619 | Handler mismatch → __destruct | yes | Two directories use different serialize_handler values | FPM |
| D | …618 | OOM corruption → stale EG() | yes | None — any endpoint | mod_php |
| E | …619 | FPM session OOM → stale BG() | yes | Producer calls session_start() | FPM |
unserialize() — only a reachable mod_php worker. The other chains depend on application behavior or FPM-specific configuration.Attack path on a real stack
Where the request travels across a typical PHP deployment, and where each flaw bites. Pick a flaw, choose detail level, then Play or click any component.
Fix & mitigations
Updating is the only complete remediation for both flaws. Temporary mitigations reduce exposure but do not remove the underlying fault — and every config change needs a full worker restart to take effect.
| Branch | Patched release | Status |
|---|---|---|
| 8.5.x | 8.5.12 | supported |
| 8.4.x | 8.4.27 | supported |
| 8.3.x | 8.3.36 | supported |
| 8.2.x | 8.2.35 | supported |
| 7.4 – 8.1 | source backport | no binary release |
| 5.4 – 7.3 | — none — | EOL · no fix |
| CVE | Temporary mitigation | Applied where |
|---|---|---|
| …618 | Enforce memory_limit=-1 so apps cannot override it | php.ini (admin), then restart workers |
| …618 | Bound post_max_size, upload_max_filesize, request size & nesting at the frontend. Do not use RLIMIT_AS/RLIMIT_DATA. | server / proxy |
| …619 | Set session.upload_progress.enabled=0 | php.ini / FPM pool (before parsing) — not ini_set() |
| …619 | On PHP 8.5 also set fatal_error_backtraces=0 | php.ini (admin), then restart workers |
Runtime ini_set() and .user.ini apply too late for the …619 mitigations — they must be set before request parsing.
session.serialize_handler before session_start(). Keep upload progress disabled; track the next PHP release for its fix.Make the call
A short defensive incident exercise. Work through the decisions in order; each answer explains the operational reason without simulating an exploit.
PHP2SHELL response drill
Scenario: an internet-facing service reports PHP 8.4.26 running via Apache mod_php.
Which deployment surface needs the fastest validation?
What is the complete first response?
Detection notes
- Public PoCs exist. Working proof-of-concept code is published by multiple researchers, and in-the-wild attempts are confirmed.
- Watch for multipart POSTs with unusually many fields or headers, large bodies, repeated out-of-memory / HTTP 500 responses, and Apache child crashes or restarts.
- Grep logs for
zend_mm_heap corruptedandAllowed memory size … exhaustedinUnknown on line 0— evidence the failure happened before application code. - For …619, correlate fatal errors / timeouts immediately followed by unusual behavior on the same worker.
- Treat absence of error-log entries as inconclusive — the stale-state path leaves no required trace.
- A focused edge control is to block
PHP_SESSION_UPLOAD_PROGRESSin multipart bodies. Reference Suricata, Sigma, ModSecurity, and Lua detections are available with the ikow PoC research. - Inventory every PHP install, including bundled/embedded ones behind appliances and containers.
php -v on CLI reflects the CLI SAPI; verify the web SAPI (mod_php / FPM) separately, then restart all workers.Detection rules
Behavioral starting points, built from the confirmed mechanism — not signatures of any one exploit. Both flaws corrupt memory, so the strongest signal is host-side: worker crashes and respawns, not a clean network payload. Treat these as illustrative and tune to your stack.
# php-fpm / apache mod_php worker crash + UAF indicators title: PHP2SHELL worker crash indicators logsource: product: linux service: php-fpm # also apache error_log for mod_php detection: crash: message|contains: - 'exited on signal 11' # SIGSEGV - 'exited on signal 6' # SIGABRT - 'zend_mm_heap corrupted' - 'out of memory' interrupted: # CVE-2026-109619 precondition message|contains: - 'Fatal error' - 'Maximum execution time' timeframe: 2m condition: crash or ( interrupted and crash ) falsepositives: - Legitimate OOM under load - Segfaults from unrelated extensions level: high
# Burst of multipart POSTs from one source (CVE-2026-109618 surface)
alert http any any -> $HTTP_SERVERS any ( \
msg:"PHP2SHELL possible OOM probe: multipart POST burst"; \
flow:to_server,established; \
http.method; content:"POST"; \
http.header; content:"multipart/form-data"; nocase; \
threshold: type both, track by_src, count 20, seconds 10; \
sid:2026109618; rev:1; )
# Flag abnormal multipart bodies; tune thresholds per app. Reduces exposure, not a fix. SecRule REQUEST_METHOD "@streq POST" \ "id:2026109618,phase:2,log,pass,msg:'PHP2SHELL: inspect multipart shape',chain" SecRule REQUEST_HEADERS:Content-Type "@rx multipart/form-data" "chain" SecRule &FILES "@gt 200" # unusually high part count — set to your real ceiling # Also block the stale-state trigger name in multipart bodies: SecRule MULTIPART_PART_HEADERS "@rx PHP_SESSION_UPLOAD_PROGRESS" \ "id:2026109619,phase:2,log,pass,msg:'PHP2SHELL: upload-progress field present'"
detection/ — Suricata, Sigma, ModSecurity, Lua) are useful to compare against, but review every rule before deploying it.PHP.net advisory PHP session advisory (23 Oct) Tenable FAQ Rapid7 ETR Sansec CERT-EU 2026-018 ikow PoC research devploit research