What PHP2Shell Is
PHP2Shell is a pair of unauthenticated remote code execution bugs in PHP itself, CVE-2026-109618 (out-of-memory corruption) and CVE-2026-109619 (stale global state). Each is rated CVSS 4.0 9.2. They were disclosed on 2026-10-21 and are exploited in the wild. They affect PHP 5.4 to 8.5 on web SAPIs, including PHP-FPM.
Edge rules are not a fix
The only real fix is a patched PHP: 8.5.12, 8.4.27, 8.3.36 or 8.2.35 upstream, or a vendor backport for older branches. Everything below only narrows the attack surface. Distros backport without changing the version, so php -v cannot tell you whether you are patched. The PHP2Shell checker reads your package list and knows the backports.
What We Tested
We tested NGINX 1.30 with PHP-FPM 8.3 on Rocky Linux 10. The full write-up is on the page for tested NGINX mitigations. The findings that matter to NGINX admins:
1. Keep request buffering on
With the default fastcgi_request_buffering on, NGINX de-chunks and buffers the request body and gives PHP-FPM a real CONTENT_LENGTH. The CVE-2026-109618 strategy of sending multipart data without a usable content length does not survive stock NGINX in front of FPM. Do not turn buffering off for PHP locations.
2. Cap the body size
client_max_body_size rejects oversized bodies, including chunked ones, with a 413 before PHP parses anything.
server {
client_max_body_size 8m; # size it to your real uploads
}
3. Disable upload progress in the pool, not in NGINX
This is the pitfall. Setting session.upload_progress.enabled=0 through fastcgi_param PHP_VALUE does not work: PHP still writes upload progress data. Set it in the PHP-FPM pool, where the value cannot be overridden:
; /etc/php-fpm.d/www.conf
php_admin_flag[session.upload_progress.enabled] = off
PHP_ADMIN_VALUE also works. PHP_VALUE from NGINX is easy to assume it works, so check what you already have:
grep -rn 'PHP_VALUE\|PHP_ADMIN_VALUE' /etc/nginx /etc/php-fpm.d
Any hardening you believed was applied through PHP_VALUE deserves a second look.
4. Reject chunked multipart
A map on the request headers combined with if ($p2s_block = "mc") { return 411; } rejects chunked multipart requests to PHP over HTTP/1.1. The complete, tested snippet is on the mitigations page above.
5. WAF rules
ModSecurity v3 rules (via nginx-module-security) blocked the PHP_SESSION_UPLOAD_PROGRESS field, oversized field names and NUL bytes in our tests.
Keep Your Config Honest
Running Gixy over your configuration is good hygiene and catches unrelated mistakes. It does not detect PHP2Shell, and it does not know whether your PHP is patched.
Checklist
- Update PHP to a patched build, then verify with a package-list check, not
php -v - Leave
fastcgi_request_bufferingat its default - Set a realistic
client_max_body_size - Move PHP ini hardening into
php_admin_flag/php_admin_valuein the pool - Run the
grepaudit forPHP_VALUEin your NGINX and FPM configs