PHP2Shell and NGINX: What Your Config Can and Cannot Do

NGINX settings can blunt some PHP2Shell attack paths. None of them replaces updating PHP.

Updated: October 2026 * 4 min read

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_buffering at its default
  • Set a realistic client_max_body_size
  • Move PHP ini hardening into php_admin_flag / php_admin_value in the pool
  • Run the grep audit for PHP_VALUE in your NGINX and FPM configs

Further Reading