Lightweight, zero-dependency Go background service & HTTP shield for Linux and Windows. Prevents, detects, logs, and mitigates php2shell pre-auth RCE exploits across PHP 5.4–8.5 without requiring application code changes.

What Is php2shell and How Do You Mitigate It?

php2shell is the community name for a family of pre-authenticated PHP remote code execution exploits built on session.upload_progress and the rfc1867 multipart parser (publicly tracked as CVE-2026-109618 and CVE-2026-109619). A single crafted multipart upload can race PHP's upload-progress bookkeeping, free session memory that the parser still references, and then reuse that memory with attacker-controlled PHPSESSID cookies to poison a session file — which is later included through an LFI sink to run arbitrary code as www-data. Related chains abuse serialized-object mismatches, Apache/PHP-FPM worker pinning for an ASLR bypass, and SAPI out-of-memory bailouts; the PHP-CGI argument-injection bug (CVE-2024-4577) is blocked by the same agent.

PHP2Shell Sentinel is a free, open-source PHP exploit mitigation tool — a single static Go binary you run on the PHP host or in front of it as a PHP WAF. It blocks upload-progress probes before the PHP parser sees them, kills poisoned sess_* files, terminates shells spawned by compromised workers, hardens php.ini, and quarantines attacking IPs at the OS firewall. It is a zero-dependency alternative to writing custom ModSecurity or Nginx rules for these chains, works on PHP 5.4–8.5, and needs no application code changes.

Animated terminal recording: a public php2shell Chain A PoC executes as www-data against an unprotected PHP 8.2.34-FPM server, then the same PoC is rejected with HTTP 403 and a quarantine drop when routed through PHP2Shell Sentinel
Live demo — the same public Chain A PoC executes as www-data without Sentinel, and is rejected with HTTP 403 (rule P2S-2026100) through Sentinel. Recorded against the reproducible lab in the repository.

Quick Install (Linux & Windows)

Default install is out-of-band. The installer starts the session, process, log, and hardening guards without changing web ports. The in-line HTTP WAF is opt-in: set proxy_enabled: true and a real backend_url, then route public traffic to listen_addr. Never enable the proxy against a placeholder backend — clients will receive 502.

Option A: One-Line Installer (Downloads binary, audits PHP, installs & starts systemd service)

curl -fsSL "https://suleman-elahi.github.io/php2shell-sentinel/install.sh" | sudo sh

Option B: Step-by-Step Binary Download via curl

# 1. Download static Linux binary
curl -fsSL "https://suleman-elahi.github.io/php2shell-sentinel/downloads/sentinel-linux-amd64" -o sentinel
chmod +x sentinel
sudo mv sentinel /usr/local/bin/sentinel

# 2. Audit PHP installation & apply php.ini virtual patches
sentinel check
sudo sentinel harden

# 3. Install & start as a persistent systemd service
#    (out-of-band guards by default; no web port changes)
sudo sentinel install
sudo sentinel start

# 4. Optional in-line WAF: set proxy_enabled=true, listen_addr=127.0.0.1:8080,
#    and backend_url=http://127.0.0.1:<real-php-port> in
#    /etc/php2shell-sentinel/sentinel.json, then restart:
sudo systemctl restart php2shell-sentinel

Option A: One-Line PowerShell Installer (Run in Elevated Administrator PowerShell)

irm "https://suleman-elahi.github.io/php2shell-sentinel/install.ps1" | iex

Option B: Step-by-Step Download & Windows Service Setup

# 1. Download static Windows binary (Run in Elevated PowerShell)
New-Item -ItemType Directory -Force -Path "C:\Program Files\PHP2ShellSentinel" | Out-Null
Invoke-WebRequest -Uri "https://suleman-elahi.github.io/php2shell-sentinel/downloads/sentinel-windows-amd64.exe" -OutFile "C:\Program Files\PHP2ShellSentinel\sentinel.exe"

# 2. Audit PHP installation & apply php.ini virtual patches
& "C:\Program Files\PHP2ShellSentinel\sentinel.exe" check
& "C:\Program Files\PHP2ShellSentinel\sentinel.exe" harden

# 3. Install & start as a Windows Background Service (Auto-Start via SCM)
#    (out-of-band guards by default; no web port changes)
& "C:\Program Files\PHP2ShellSentinel\sentinel.exe" install
& "C:\Program Files\PHP2ShellSentinel\sentinel.exe" start

# 4. Optional in-line WAF: set proxy_enabled=true, listen_addr,
#    and backend_url in C:\ProgramData\php2shell-sentinel\sentinel.json,
#    then restart the service.

Deployment Modes

Choose out-of-band host protection, in-line HTTP inspection, or both. The proxy is intentionally disabled by default so a fresh install cannot break a host whose PHP backend is not on a guessed address.

Mode How to run Protects Traffic change
Out-of-band (default) sentinel install / sentinel run Session poisoning, spawned shells, runaway workers, crash/OOM log signals, php.ini hardening, optional firewall bans None
In-line WAF sentinel run -proxy -listen 127.0.0.1:8080 -backend http://127.0.0.1:8081 All out-of-band protections plus pre-parser blocking of multipart, request, cookie, response, and scanner vectors Route public traffic to listen_addr; keep the PHP backend private

Enable the in-line shield

Point backend_url at the real PHP listener (FPM, Apache, nginx, or IIS), then route public traffic to listen_addr.

# /etc/php2shell-sentinel/sentinel.json
"proxy_enabled": true,
"listen_addr": "127.0.0.1:8080",
"backend_url": "http://127.0.0.1:8081"

# restart, then confirm the backend is reachable
sudo systemctl restart php2shell-sentinel
sudo journalctl -u php2shell-sentinel -n 20
curl -s http://127.0.0.1:9095/status

If the backend is unreachable, Sentinel logs backend_unreachable and the proxy returns 502. Fix backend_url, or run with -no-proxy if only out-of-band protection is intended.

Direct Downloads

sentinel-linux-amd64

Static Linux x86_64 binary (CGO_ENABLED=0). Includes WAF proxy, /proc watchdog, session guard, and systemd manager.

Download Linux Binary

sentinel-windows-amd64.exe

Static Windows x86_64 executable. Native Windows Service Control Manager (SCM) & Win32 Toolhelp32 process watchdog.

Download Windows .exe

Configuration & Checksums

Default JSON configuration template (out-of-band by default; enable the proxy explicitly), installer scripts, and SHA-256 checksums for binary verification.

sentinel.example.json SHA256SUMS.txt install.sh install.ps1

Verified Results (2026-10-23)

Tested against public php2shell PoCs and a deliberately vulnerable PHP 8.2.34-FPM + nginx lab: first exploitability without Sentinel, then the same requests through Sentinel.

Check Result
Go unit tests (go test ./...) PASS — all packages
Repository safe lab (harmless replay) PASS — 403 P2S-2026100
Public Chain A RCE, no Sentinel RCE CONFIRMED — uid=33(www-data)
Public Chain A RCE through Sentinel BLOCKED — 403 P2S-2026100, no command execution
php2shell-scanner, no Sentinel / through Sentinel VULNERABLE / BLOCKED — 403 P2S-2026107-SCAN
Rule-by-rule WAF matrix 19/19 PASS
Process watchdog PASS — killed long-lived shell children, P2S-PROC-EXEC
Session-file guard PASS — removed/quarantined poisoned sess_* files
php.ini hardener PASS — upload_progress=Off, use_only_cookies=On, backup created
Exact binary as in-line WAF PASS — clean 200; Chain A 403

Limitations: normal process sampling runs every 150ms; a malicious WAF finding triggers a 10ms burst for 5s so short-lived system('id') children are far more likely to be caught. Common PHP version strings are scrubbed from small, uncompressed text/JSON/XML responses (scrub_php_version_in_body), but large, compressed, or non-text output is still application-owned. A scanner may report INCONCLUSIVE when its probe is rejected with 403; that is expected — the probe never reached PHP. The 3-probe/60s quarantine is configurable (probe_threshold, probe_window). Sentinel is mitigation, not a substitute for patching PHP and disabling session.upload_progress.enabled.

What Works with "Zero Application Modifications"

Sentinel can run as an in-line HTTP reverse proxy shield or completely out-of-band (-no-proxy -firewall) without altering existing Apache, Nginx, IIS, or PHP ports.

Capability How Sentinel Does It Passively App Changes?
Blocking Spawned Shells Scans OS process tree (/proc on Linux, Win32 CreateToolhelp32Snapshot on Windows) every 150ms, with a 10ms burst for 5s after a WAF finding and kills shells (sh, bash, cmd.exe, powershell.exe, nc, curl) spawned by PHP workers. No
Deleting Poisoned Sessions Watches /var/lib/php/sessions, /tmp, C:\Windows\Temp, and C:\xampp\tmp for sess_* files containing <?php, upload_progress_ state, |O:/|C: object gadgets, or > 4 MiB inflation and quarantines/deletes them immediately. Legitimate upload_progress_...|a: arrays are cleaned as upload state, not mislabelled as handler mismatch. No
Detecting Crashes & OOM Bailouts Reads directly from journalctl (Linux), Windows Application Event Log (wevtutil), and web error logs for in Unknown on line 0, Session object destruction failed, and SIGSEGV. No
Quarantining Attacking IPs Automatically inserts DROP/Block rules into the OS firewall (iptables on Linux, netsh advfirewall on Windows). No
Deep Multipart UAF Prevention When run in-line, aborts PHP_SESSION_UPLOAD_PROGRESS, blocks two-phase stalled uploads (< 900ms chunk timeout), caps per-IP concurrent multipart connections (defeating 149-worker pinning), and scrubs Set-Cookie: PHPSESSID heap leaks. Point HTTP backend

CLI & Service Operations Reference

Linux Commands

# Audit local PHP version & php.ini files (read-only)
sentinel check

# Apply virtual patches (session.upload_progress.enabled = Off) with .bak backup
sudo sentinel harden

# Run in Zero-Touch Out-of-Band Mode (watches /proc, sessions, journald & iptables)
sudo sentinel run -no-proxy -firewall -log-file /var/log/php2shell-sentinel.log

# Check systemd service status, live telemetry & journal logs
sudo systemctl status php2shell-sentinel
sudo journalctl -u php2shell-sentinel -f
sentinel status

Windows Commands (Elevated PowerShell / Administrator CMD)

# Audit local Windows PHP installation (XAMPP / WAMP / Laragon / IIS)
sentinel.exe check -path C:\xampp\php

# Apply php.ini virtual patches with automatic .bak backup
sentinel.exe harden -path C:\xampp\php\php.ini

# Run in Zero-Touch Out-of-Band Mode on Windows (Win32 processes, sess_*, Event Log, Windows Firewall)
sentinel.exe run -no-proxy -firewall -log-file C:\ProgramData\php2shell-sentinel\sentinel.log

# Query Windows Service status, live telemetry, and Windows Firewall rules
Get-Service PHP2ShellSentinel
sc.exe query PHP2ShellSentinel
sentinel.exe status
netsh advfirewall firewall show rule name=all | findstr PHP2ShellSentinel

Built-In Detection & Mitigation Rules

Rule ID CVE / Chain Target Vector & Mitigation
P2S-2026100 CVE-2026-109618 / 109619 Blocks or strips PHP_SESSION_UPLOAD_PROGRESS in POST/PUT/PATCH multipart bodies (including multipart/form-data,boundary=x).
P2S-2026100-STALL CVE-2026-109618 / 109619 Aborts stalled multipart uploads (> 900ms inter-chunk pause) before php_session_track_init() frees arData.
P2S-2026100-STREAM CVE-2026-109618 / 109619 Sliding-window scanning of large multipart uploads with pooled buffers, preventing padding bypasses before PHP parses the body.
P2S-2026101 PR #22113 Blocks name="PHPSESSID" in multipart request bodies (prevents session.use_only_cookies bypass).
P2S-2026102 Chain A (Session LFI) Blocks PHP tags (<?php, <?=) inside multipart upload filenames.
P2S-2026103 Chain C (Handler Mismatch) Blocks |O:... / |C:... serialized object injection inside upload filenames. Plain serialized arrays (|a:) used by upload-progress state are not treated as object gadgets.
P2S-2026104 Chain E & Heap Spray Blocks upload filenames > 200 bytes (stops 231B ZendMM 256B bin spray and 10KB+ session inflation).
P2S-2026105 Chain D (SAPI OOM) Blocks Transfer-Encoding: chunked on multipart uploads (post_max_size bypass) and excessive part counts.
P2S-2026106 Chain A (LFI / pearcmd) Blocks LFI paths referencing sess_* or pearcmd.php (+config-create+).
P2S-2026107 / 108 Scanner / Heap Shape Blocks a[][a][a]... nested bracket probes and empty-boundary discrepancy probes; auto-bans after 3 probes/60s (configurable).
P2S-2026109 / 111 / 112 Pure HTTP ASLR Bypass & Response Guard Blocks forged binary Cookie: PHPSESSID pointers, scrubs 800KB Set-Cookie: PHPSESSID heap leaks, and quarantines Session object destruction failed / PHP OOM responses.
P2S-2026116 Version Disclosure Scrub Replaces PHP 8.x.y / PHP Version 8.x.y strings in small, uncompressed text, JSON, and XML responses and fixes Content-Length.
P2S-20244577 CVE-2024-4577 Blocks PHP-CGI soft-hyphen (%ADd) and -d allow_url_include / auto_prepend_file argument injection.

Frequently Asked Questions

What is php2shell?

php2shell is the community name for a family of pre-authenticated PHP remote code execution exploits built on session.upload_progress and the rfc1867 multipart parser. A crafted multipart upload races PHP's upload-progress bookkeeping to trigger a use-after-free, poisons a session file (typically via a forged PHPSESSID), and includes it through an LFI sink to run code as www-data. Public PoCs chain several additional stages — serialized handler mismatch, worker pinning for an ASLR bypass, and SAPI OOM bailouts.

Which CVEs does PHP2Shell Sentinel mitigate?

CVE-2026-109618 and CVE-2026-109619 (the session.upload_progress / rfc1867 UAF chains) and CVE-2024-4577 (PHP-CGI argument injection on Windows and Linux). It also blocks the LFI-to-RCE, serialized-object injection, ASLR bypass and OOM-bailout stages used by public PoCs.

How do I mitigate a PHP session.upload_progress RCE without patching PHP?

Set session.upload_progress.enabled = Off, upgrade PHP to a fixed release, and run a compensating control. Sentinel blocks the upload-progress field, aborts stalled multipart uploads (sub-second inter-chunk deadline), cleans poisoned session files, and quarantines attacking IPs — all without changing application code.

Does it require application or framework changes?

No. Sentinel runs as a host agent out-of-band by default (session guard, process watchdog, log tailer, php.ini hardening, optional firewall bans) and can be enabled as an in-line HTTP reverse-proxy shield by pointing backend_url at your existing PHP listener. Apache, nginx, IIS, PHP-FPM, XAMPP, WAMP and Laragon layouts are supported on Linux and Windows.

Is PHP2Shell Sentinel free and open source?

Yes — MIT licensed, written in Go, shipped as a single static binary with no runtime dependencies, and published with SHA-256 checksums for download verification.

Is Sentinel a replacement for patching PHP?

No — it is mitigation. Keep session.upload_progress.enabled = Off, disable display_errors in production, and upgrade to a fixed PHP release (8.2.35 / 8.3.36 / 8.4.27 / 8.5.12 or newer for the affected lines). Sentinel buys time and blocks exploitation attempts in the meantime.

How can I verify that it actually blocks the exploit?

The project publishes verification results: a public Chain A PoC that achieves uid=33(www-data) on a vulnerable PHP 8.2.34-FPM lab is blocked with HTTP 403 (rule P2S-2026100) when routed through Sentinel, a 19-rule WAF matrix passes, and scanner probes are rejected before reaching the PHP parser. See Verified Results and the GitHub repository.