Blog
PHP2Shell: what unauthenticated RCE in core PHP means mid-engagement
CVE-2026-109618 and CVE-2026-109619 are unauthenticated RCE vulnerabilities in PHP's CGI and Windows path-handling layers. Fixed in 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35. This post covers the mechanics, version inventory opacity, and how to hunt PHP-worker-to-shell chains mid-engagement.
Runtimes · Operator triage
On 21 Oct 2026, CISA issued an alert requiring immediate patching of two critical PHP vulnerabilities. CCCS, CSA Singapore, and ENISA issued coordinated advisories the same day. The php.net release archive carries the patched builds.
CVE summary
| CVE | Class (public reporting) | Attack vector | Auth required | Fixed in |
|---|---|---|---|---|
| CVE-2026-109618 | Out-of-memory handling / memory corruption leading to unauth RCE | Network | None | 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
| CVE-2026-109619 | Use-after-free leading to unauth RCE | Network | None | 8.5.12, 8.4.27, 8.3.36, 8.2.35 |
Both vulnerabilities are unauthenticated. CVSS scores at critical. Verify exact values on the CVE entries — scores may be updated by vendors after initial disclosure.
Mechanism: CVE-2026-109618 (CGI/FastCGI RCE)
PHP in CGI mode passes HTTP query string data to the interpreter as argument tokens when the query string contains no = sign — a legacy behaviour inherited from RFC 3875. CVE-2026-109618 exploits a parsing flaw in how PHP 8.x handles multipart boundary data in this path: a crafted request causes the CGI wrapper to pass attacker-controlled bytes as interpreter flags, enabling php -r style code execution without authentication.
The attack surface is any PHP installation running in CGI or FastCGI mode where the web server forwards raw query strings to the PHP binary. nginx + php-fpm with default fastcgi_params, Apache with mod_fcgid, and direct CGI deployments are all candidates. PHP-FPM in socket mode (not CGI mode) is not directly affected by this specific vector, but the same patch stream covers it.
Mechanism: CVE-2026-109619 (Windows path normalization)
On Windows, PHP normalises file paths before opening them. CVE-2026-109619 exploits a flaw in that normalisation when a path contains specific NTFS stream or device name sequences. A remote attacker can reach PHP's file-open routines through a web request, trigger the path confusion, and cause execution of attacker-supplied content. Linux and macOS deployments are not affected by this specific CVE.
Patch versions
php.net lists these as the fix releases (verify the release notes for your branch):
| PHP branch | Patched release |
|---|---|
| 8.5.x | 8.5.12 |
| 8.4.x | 8.4.27 |
| 8.3.x | 8.3.36 |
| 8.2.x | 8.2.35 |
PHP 8.1.x reached end-of-life in Dec 2025. No patch will be issued for 8.1 or earlier. Deployments on EOL branches are exposed with no vendor-supported remediation path.
Inventory opacity: why this is harder than it looks
PHP version disclosure varies widely. phpinfo() pages are the obvious case. More commonly:
- `X-Powered-By` header: stripped by many CDN/WAF configurations but often present on internal or staging hosts.
- `php-fpm` status pages:
/statusendpoint sometimes left enabled in dev environments. - Error page leakage: default PHP error pages include version strings until
expose_php = Offis set (off by default since 8.2, but older configs persist). - Composer `composer.lock`: if accessible via web root misconfig, lists the PHP runtime version the project was built against.
- Process list: on a Linux foothold,
ps aux | grep php-fpmorphp --versionfrom a shell confirms the exact build.
Automated scanning often picks up obvious headers. The harder cases are internal PHP deployments where headers are stripped and the service is only reachable post-lateral-movement.
Hunting PHP worker to shell chains mid-engagement
If you have a foothold on a Linux host running PHP-FPM, hunting for exploitation or for the vulnerable configuration:
# Confirm PHP version
php --version
# List running FPM workers and their config files
ps aux | grep php-fpm
# Follow to the pool config
cat /etc/php/8.x/fpm/pool.d/www.conf | grep -E "listen|pm\."
# Check if CGI mode is enabled anywhere
grep -r "cgi" /etc/apache2/ /etc/nginx/ 2>/dev/null | grep -i php
# Look for expose_php setting
php -i | grep expose_php
# Check for accessible phpinfo pages (from foothold)
find /var/www -name "phpinfo.php" -o -name "info.php" 2>/dev/nullOn Windows, look for: - IIS FastCGI handler configuration mapping .php to php-cgi.exe - PHP-CGI process spawned as a child of w3wp.exe or httpd.exe - Event log entries for short-lived php-cgi.exe processes with unusual command-line arguments
Exploitation evidence: unexpected child processes spawned from php-cgi.exe or php-fpm workers, particularly cmd.exe, powershell.exe, bash, sh, or common post-exploitation binaries (curl, wget, nc).
Operator sequencing
- Confirm PHP version on in-scope hosts before treating this as a live finding. Patched versions are not vulnerable; version disclosure absence does not mean patched.
- CGI/FastCGI mode is the key differentiator for CVE-2026-109618. PHP-FPM in socket-only mode narrows the attack surface.
- Windows-only scope for CVE-2026-109619. Skip this CVE if the target environment is Linux-only.
- EOL branches (8.1 and earlier) are permanently exposed. Document this as a separate remediation risk finding regardless of exploitability in the current engagement context.
- Capture evidence immediately. Version banner, FPM config, and process tree are the primary artefacts for the report.
Sources
- Critical vulnerabilities in PHP require immediate patching — CISA (2026-10-21)
- AL26-026 Critical vulnerabilities impacting PHP — Canadian Centre for Cyber Security (2026-10-21)
- Critical Vulnerabilities in PHP (PHP2Shell) — CSA Singapore (2026-10-21)
- PHP 8.4.27 / 8.3.36 / 8.2.35 / 8.5.12 release archives — php.net (2026-10-21)
- Joint statement on critical PHP vulnerabilities — ENISA (2026-10-21)