PHP2Shell.fyi Check a site

Reduce exposure until you update

Only a PHP update fully fixes PHP2Shell. The settings on this page make some attacks harder while you wait for it. The flaw stays in place.

Last reviewed . Rules of .

Update first. Install PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12, or a patched build from your Linux distribution or host. Then restart every PHP worker.

On PHP 8.1 or older, ask your vendor for a patched build, or move to a supported branch. See PHP 7.4, 8.0 and 8.1.

Where each measure comes from

Each measure carries a label for its source:

Change one thing at a time, and test your site after each change. Restart every PHP worker after you change a PHP setting.

Measures, in order

Against CVE-2026-109618 (out-of-memory corruption)

  1. php.net advisory Set memory_limit=-1 in a way that apps cannot override, for example php_admin_value in the FPM pool or the Apache config. Make sure no pool, directory or app setting puts a finite limit back. This removes the memory-limit failure that an attacker can control. A real allocation failure can still reach the flaw.
  2. php.net advisory Put a memory cap outside PHP: a container or cgroup limit. Ideally it kills only the affected worker. Do not use RLIMIT_AS or RLIMIT_DATA instead: they can cause the failure that triggers the flaw.
    GHSA A container or cgroup kill can also kill the PHP-FPM master and every worker, unless each worker has its own group.
  3. php.net advisory Set a low post_max_size: 8M if the app takes no file uploads, 32M if it does. Keep upload_max_filesize below post_max_size.
  4. php.net advisory Limit requests at the web server or proxy: decoded body size, number of input fields, number of multipart parts, number of headers and nesting depth. These limits must also cover requests without a usable Content-Length.
    GHSA Also limit the headers inside each multipart part, and the number of uploads.
  5. GHSA Lower max_input_nesting_level. Bound the number of input variables and multipart parts.
    Our advice In PHP, the matching settings are max_input_nesting_level, max_input_vars and max_multipart_body_parts. Set them as low as your app allows.
  6. GHSA If your app does not use multipart/form-data (forms with file uploads), block those requests at the frontend, before they reach PHP.

Against CVE-2026-109619 (stale state from an earlier request)

  1. php.net advisory Set session.upload_progress.enabled=0 in php.ini, the FPM pool or the server config. Do not use ini_set() or .user.ini: they apply too late. Restart every worker. This blocks the confirmed session paths, not every variant.
  2. php.net advisory On PHP 8.5, set fatal_error_backtraces=0 and restart every worker. This blocks only the confirmed fatal-backtrace path.
  3. php.net advisory Remove invalid or deprecated settings that are applied per request and print a warning before PHP starts the request.
    GHSA Examples: auto_detect_line_endings=1, legacy assert.* settings (8.3 and newer), legacy session settings (8.4 and newer), explicit mbstring.http_input, mbstring.http_output, mbstring.internal_encoding and iconv.*_encoding values, invalid memory_limit, date.timezone or zend.assertions values, and paths that open_basedir rejects. On Apache mod_php, .htaccess and php_value, php_flag and php_admin_* lines apply before the request starts. On PHP-FPM this applies only when the web server sends PHP_VALUE or PHP_ADMIN_VALUE. Prefer php.ini, FPM pool or server config that applies at startup.
    Our advice A valid value prints no warning. php_admin_value[memory_limit] = -1 from step 1 is fine.
  4. php.net advisory Fix fatal errors and execution timeouts that an attacker can reach. This includes failures in callbacks, upload or import processing, and cleanup.
    GHSA Treat a Maximum execution time exceeded error like any other fatal error.
  5. GHSA If performance allows, set pm.max_requests=1 so each PHP-FPM worker handles one request. Recycling workers lowers the chance of an attack without removing it.
    php2shell.com The researchers also suggest a lower pm.max_requests.

For both

  1. php2shell.com Use SELinux or AppArmor to limit what a compromised PHP worker can do.
  2. Our advice Keep a WAF in front of the site and lock the origin. See WAF and CDN.

Configuration examples

These follow the measures above. Fit the values to your app; the file paths depend on your system. Restart every PHP worker after a change.

php.ini

; Interim only. Restore a finite memory_limit after you update.
memory_limit = -1
post_max_size = 8M                      ; 32M if the app takes uploads
upload_max_filesize = 6M                ; keep it below post_max_size
session.upload_progress.enabled = 0
fatal_error_backtraces = 0              ; PHP 8.5 only

An app can raise memory_limit again at runtime. php_admin_value, as below, stops that.

PHP-FPM pool (for example www.conf)

; php_admin_* values cannot be changed by the app.
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 6M
php_admin_flag[session.upload_progress.enabled] = off
; PHP 8.5 only. On older PHP, delete the next line: FPM logs an error for it.
php_admin_flag[fatal_error_backtraces] = off
; Only if performance allows. Remove the ; to turn it on.
; pm.max_requests = 1

Apache with mod_php (virtual host or server config)

php_admin_value memory_limit -1
php_admin_value post_max_size 8M
php_admin_value upload_max_filesize 6M
php_admin_flag session.upload_progress.enabled off
# PHP 8.5 only. Apache does not allow a comment on the same line as a directive.
php_admin_flag fatal_error_backtraces off

Run apachectl configtest before you restart Apache. On mod_php these lines apply before each request starts. Check every value with care: an invalid value prints a warning at that early point, and that warning is one of the paths into CVE-2026-109619.

Block multipart requests if the app does not need them

These are our examples. Test them first, because they also block normal file uploads and some forms.

# nginx (server block)
if ($http_content_type ~* "multipart") { return 403; }
# Apache (mod_rewrite)
RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart [NC]
RewriteRule ^ - [F]

What does not help

WAF and CDN

A web application firewall (WAF) or CDN with PHP2Shell rules can stop some attack requests. The researchers say that partners prepared detections and temporary mitigations, and that a protective rule does not replace a PHP update (php2shell.com).

A WAF sees only the traffic that passes through it. A request sent straight to your origin server skips it.

Our advice Lock the origin: let your server accept web traffic only from your CDN or WAF, for example with a firewall allowlist of its addresses. Keep the WAF rules on until you update PHP, and after.

After you update

  1. Restart everything that runs PHP. Restart Apache, PHP-FPM and every long-running PHP worker (php2shell.com). Our advice Rebuild and redeploy container images from the updated base image. Check every PHP runtime on the host, including control panels.
  2. Check the PHP that serves the web. Our advice php -v on the command line can show a different PHP than the one your web server uses. Check the PHP-FPM pool or the admin screen of your app or host. Distribution packages often keep the old upstream number, so compare the package version (dpkg -l or rpm -q) with your vendor's fixed version. See Fixed versions.
  3. Restore a finite memory_limit. If you set -1 as a stopgap, set a real limit again. Fit it to your request-size limits and the memory your app really uses. Keep post_max_size well below that memory budget (php2shell.com).
  4. Know the new hard memory limit. The fixed releases change how PHP handles out-of-memory. PHP now stops a script at the next point where it can stop cleanly when it passes memory_limit. If memory use reaches a second, higher limit, the process ends at once (GHSA). The new setting memory_hard_limit_percent sets that second limit. It is unset by default, which works like -1: two times memory_limit up to 1G, and memory_limit plus 1G above 1G. Other values must be 100 or more. At the hard limit, PHP does not run shutdown functions (php-src source).
  5. Keep session upload progress off if you do not use it. The GHSA says this is prudent, because attackers now look closely at this little-used feature.
  6. Keep input limits tight. Limit max_input_nesting_level to what your app needs (php2shell.com).
  7. Remove stopgaps you no longer need. Our advice For example pm.max_requests=1, if it slows the site.
  8. If PHP crashes after the update. php-src issue GH-24488 reports zend_mm_heap corrupted crashes in 8.4.27 and 8.5.12 with SimpleXML. It is a crash, not a reported vulnerability. The fix is in the php-src source since 2026-10-22, but not yet in a release. Our advice Do not downgrade: an older release brings both flaws back. Watch php.net for a follow-up release.

Check your logs

Clean logs prove nothing. A failure can happen before PHP writes a message, and old logs may have left out deprecations and other messages. An audit covers only the pages and app states that ran during it. Logs add to a review of your configuration and your app; they do not replace it (GHSA).

What the PHP security team says to look for (GHSA)

Run the audit on an isolated copy of the site, with log_errors=On, a working error_log and error_reporting=E_ALL in the startup configuration. Read the Apache, PHP-FPM, reverse proxy and service logs for:

Signs the researchers name (php2shell.com)

These signs do not prove an attack. Their absence does not prove that no attack happened (php2shell.com).

Rotate secrets on exposed hosts

The flaws can leak PHP process memory. That memory can hold passwords, login tokens, API keys and certificates from other requests or from the server (php2shell.com).

Our advice If a host ran an affected PHP version on the public internet, rotate the secrets that PHP could read, after you update:

Sources

Check your site

The checker shows which PHP version your site reports in public. It sends only ordinary GET requests and does not test these measures.