PHP2Shell Mitigation: Configuration Steps and Why It's Not Enough

Official PHP2Shell adjustments buy time, not security. Learn where to apply them, how to restart PHP workers correctly, and what to do before the official patch.

by Cleverson Gouvêa

PHP2Shell Mitigation: Configuration Steps and Why It's Not Enough

The PHP2Shell mitigation you apply today in php.ini buys time, but it doesn't close the door. The two flaws (CVE-2026-109618 and CVE-2026-109619) allow remote code execution without login on virtually any exposed PHP server. In this guide, I'll show you what to configure while the update isn't out, how to restart all workers correctly, and why the PHP team itself states that none of these measures replace the patch.

TL;DR

  • PHP2Shell consists of two critical vulnerabilities (CVSS 4.0 = 9.2), without authentication. The fix was released on 10/21/2026 for versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35.
  • The official PHP2Shell mitigation has three adjustments: memory_limit=-1, session.upload_progress.enabled=0, and, in PHP 8.5, fatal_error_backtraces=0. These reduce exposure, but do not make the server secure.
  • Configuration only takes effect after each PHP process is restarted: FPM, Apache with mod_php, queues, long-running workers, and containers.
  • PHP 7.4 to 8.1 only have minimal source code backports. PHP 5.4 to 7.3 have no fix at all: the solution is to migrate.
  • On 10/23, an extra alert was released (CVE-2026-115560). Those who have already disabled upload progress are covered until the next regular release.

What is PHP2Shell and Why the Urgency

PHP2Shell is the nickname for two core PHP vulnerabilities that allow an anonymous attacker to run code on your server with a well-crafted HTTP request. It doesn't require a password, a vulnerable plugin, or an application error.

  • CVE-2026-109618 is an out-of-memory corruption. PHP runs out of memory in the middle of request assembly, leaves internal structures incomplete, and then uses this invalid data during cleanup.
  • CVE-2026-109619 is a stale global state issue, a use-after-free between requests. An internal state survives the previous request's memory, and the next request handled by the same worker acts upon this remnant.

The timeline explains the urgency. According to Tenable's FAQ, Amazon recorded an exploitation attempt on its honeypots on 10/17, four days before disclosure. Details leaked on social media on 10/20, ahead of the agreed-upon date, and PHP released the patch early on 10/21/2026. watchTowr reports exploitation attempts on its honeypot network since the 21st.

The scope is also alarming. Palo Alto Networks (owner of Unit 42) reported identifying over 22.6 million potentially vulnerable exposed instances, according to TechTarget. Other counts are lower, as each company measures differently. The message is the same for all: if you run WordPress, Laravel, Moodle, or a custom PHP system, you are in scope.

Which Versions Are Affected

PHP Branch Status Action
8.5 Fixed in 8.5.12 Update immediately
8.4 Fixed in 8.4.27 Update immediately
8.3 Fixed in 8.3.36 Update immediately
8.2 Fixed in 8.2.35 Update and plan for end-of-life (EOL on 12/31/2026)
7.4, 8.0, and 8.1 No official release; only minimal source code backports Distro/LTS package or migrate to 8.2+
5.4 to 7.3 No fix Migrate or take offline

PHP2Shell Mitigation: Three Official Adjustments

The PHP security advisory lists three PHP2Shell mitigation configurations for those who cannot update yet. Each addresses a specific exploitation path, and none cover everything.

1. memory_limit=-1 (against CVE-2026-109618)

The out-of-memory flaw relies on PHP hitting a memory ceiling at a predictable point. With memory_limit=-1, this per-request ceiling ceases to exist. PHP requests that the adjustment be made in a way that the application cannot override it, for example with php_admin_value in the FPM pool or Apache configuration, and that you verify no pool, directory, or application re-establishes a finite limit.

The PHP team issues a warning that catches many off guard: **do not substitute with RLIMIT_AS or RLIMIT_DATA**, because these operating system limits can precisely trigger the vulnerable allocation flaw.

2. session.upload_progress.enabled=0 (against CVE-2026-109619)

The session upload progress feature is enabled by default and is one of the confirmed exploitation paths. Disabling it closes this path. PHP itself warns that this "blocks confirmed session paths, but not other variants."

3. fatal_error_backtraces=0 (PHP 8.5 only)

In PHP 8.5, the fatal error backtrace is another confirmed path for CVE-2026-109619. Disabling it blocks **only** this path.

Where to Place (and Where Not To)

The golden rule of PHP2Shell mitigation is simple: the adjustment must take effect **before** PHP processes the request. Use php.ini, the FPM pool, or the web server configuration. **Do not rely on ini_set() or .user.ini**, because they take effect too late.

; /etc/php/8.3/fpm/pool.d/www.conf (adjust path to your version)
php_admin_value[memory_limit] = -1
php_admin_value[session.upload_progress.enabled] = 0
; PHP 8.5 only:
php_admin_value[fatal_error_backtraces] = 0

The CIQ guide for Rocky Linux adds two optional reinforcements: post_max_size = 8M when the application doesn't receive uploads (32M when it does, with upload_max_filesize below that) and pm.max_requests = 1 in FPM, which prevents state inheritance between requests at the cost of significant performance.

Why PHP2Shell Mitigation Isn't Enough

Here lies the most costly mistake: applying the three adjustments, seeing the site online, and crossing the task off your list. PHP is direct in its warning: these measures reduce exposure, **but do not make the installation secure**. The only complete fix is to update.

There are four practical reasons:

  1. Partial Coverage. PHP2Shell mitigation closes the confirmed paths. Variants that no one has published yet remain open.
  2. memory_limit=-1 does not eliminate the memory flaw. According to CIQ, `mmap()` failures or other allocations can still reach the vulnerable code. You're only removing the easiest trigger.
  3. Real Side Effect. Without a memory limit, a script with an infinite loop or a heavy report can consume the server's entire RAM and trigger the Linux OOM killer. The recommendation is to set a limit per container or cgroup, preferably one group per worker. PHP treats this as an availability barrier, not as complete mitigation.
  4. WAF helps, but isn't decisive. Cloudflare published emergency rules, but they only protect traffic passing through it, and the company itself acknowledges that request-based rules do not reliably separate attacks from legitimate traffic.

Quick Decision Table

Adjustment Blocks Does Not Block Cost
memory_limit=-1 Predictable OOM trigger mmap() failures and other allocations Risk of a script crashing the server
session.upload_progress.enabled=0 Confirmed session paths Other variants of 109619 Removes native upload progress bar
fatal_error_backtraces=0 (8.5) Fatal backtrace path Other paths Less detail in error logs
pm.max_requests=1 State inheritance between requests The OOM flaw Significant performance drop
WAF (Cloudflare etc.) Part of known payloads Traffic not passing through WAF False positives

The CISA, the U.S. cybersecurity agency, went further: it recommended taking offline PHP systems that cannot be patched or that run PHP 8.1 or older. CERT-EU suggests isolating exposed applications until the fix is applied and verified.

How to Restart Workers Without Leaving Old Processes Behind

New configuration and new binaries only take effect when **each PHP process** is restarted. PHP reiterates this in each advisory item: "restart all workers." In practice, this is where many fixes fall short: without a restart, PHP2Shell mitigation only exists in the file.

PHP-FPM and Apache

# Debian/Ubuntu (adjust version)
sudo systemctl restart php8.3-fpm
# Apache with mod_php: complete restart, not just graceful
sudo systemctl restart apache2   # or httpd on RHEL/Rocky

I prefer `restart` over `reload` for a security fix. It's a cut of a few seconds, which you schedule, in exchange for the certainty that no old process survived.

The Processes Everyone Forgets

CIQ reminds us that all PHP processes need to restart, **including long-running CLI jobs**. The checklist includes:

  • Laravel Queues: php artisan queue:restart (or Horizon restart) and Octane with php artisan octane:reload.
  • Supervisor Programs: sudo supervisorctl restart all for groups running PHP.
  • Moodle: cron and ad hoc task executors that run in a loop.
  • Containers: docker restart reuses the same image. You need to download the patched image and **recreate** the container (docker compose pull && docker compose up -d).
  • Applications that embed their own PHP: depend on vendor updates.

How to Verify Success

Do not rely on `php -v` from the terminal: it shows the CLI, which might be a different binary. Verify what the web server is using:

  1. Create a temporary file, accessible only by your IP, with <?php echo PHP_VERSION, ' ', ini_get('memory_limit'), ' ', ini_get('session.upload_progress.enabled');. Access it, verify, and **delete the file**.
  2. Check the start time of processes with ps -o pid,lstart,cmd -C php-fpm8.3. Everything needs to be newer than the package installation.
  3. On Debian/Ubuntu, `needrestart` lists services that are still loading old libraries.

72-Hour Plan: What to Do, in What Order

If you have an exposed PHP server and haven't updated yet, this is the order I would follow to combine PHP2Shell mitigation and updating:

  1. Inventory (hour 0). List all hosts with PHP, version, SAPI (FPM, mod_php, CGI), and which ones are exposed to the internet. mod_php is the most exposed, with confirmed RCE in default configuration.
  2. Preserve logs. Before restarting or rebuilding, save your web server logs. Amazon recommends investigating from **10/17**.
  3. Apply PHP2Shell mitigation (hours 1-2) using the three adjustments, in the right place, and restart all workers.
  4. Update (hours 2-24). Branches 8.2 to 8.5: use your distribution's package or the repository you use. 7.4 to 8.1: use the distro's LTS package, if available. 5.4 to 7.3: isolate and schedule migration.
  5. Restart again and verify with the three tests above.
  6. Hunt for Traces (hours 24-72). Look for new PHP files in upload folders, administrative users created in recent days, or strange cron jobs. As analysts interviewed by TechTarget remind us, updating does not remove access an attacker may have already gained. On an exposed server without a patch, change the credentials that the PHP worker had in memory (database, APIs, SMTP).
  7. Only then revert what is inconvenient, such as `memory_limit=-1`, restoring a reasonable finite limit.

When NOT to Blindly Apply PHP2Shell Mitigation

  • Small, shared server with many sites: `memory_limit=-1` without cgroup is an invitation for one site to crash all of them. In this case, updating directly is often safer than mitigating.
  • Application that shows an upload progress bar using the native session feature: notify the team beforehand, because the bar will stop working.
  • Environment you cannot restart outside a maintenance window: the adjustment is useless until the restart. Negotiate the window now.

The 10/23 Alert: CVE-2026-115560

Two days after the patch, PHP published an informational advisory about **CVE-2026-115560**, an RCE vector that affects even already patched versions, such as 8.5.12. The good news: it only exists if the application defines session.serialize_handler as php_binary or php_serialize in the configuration and switches to php at runtime with ini_set() before session_start(), with upload progress still enabled.

PHP classified the scenario as unlikely and will fix it **in the next regular release**. The guidance is to keep session.upload_progress.enabled=0 until then. If you applied this PHP2Shell mitigation item on the 21st, you don't need to do anything else, as The Hacker News summarized. Therefore, do not revert this adjustment along with `memory_limit` after the patch.

What This Means for Moodle, WordPress, and Laravel

PHP2Shell affects the interpreter, not the application. So, there's no point waiting for a Moodle or WordPress update: the server's PHP package is what resolves it.

For **Moodle**, the focus is on memory. Moodle itself raises the limit at runtime for heavy tasks, such as course backups and reports. With memory_limit=-1, this ceases to be an issue, but a large backup can then consume all available RAM. If you are still on PHP 8.1 due to an older Moodle version, now is the time to review the server requirements for Moodle 5.x and plan the upgrade.

For **WordPress** and **Laravel**, the main concern is with long-running workers (queues, Octane, system cron) and shared hosting where you don't control PHP. If your provider hasn't informed you of the version and restart date, ask in writing.

PHP2Shell mitigation also doesn't replace the basics. If the server has never gone through a Linux server hardening checklist, or if it still lacks WAF, fail2ban, and rate limiting, the next flaw will find the same door open.

How Agathas Web Addresses This

The question this incident left for many companies isn't technical: it's **who was on call on the 21st**. When a fix is released at 2 PM UTC on a Wednesday, someone needs to inventory, apply, restart, verify, and hunt for traces on the same day. If that person doesn't exist on your team, that's the service we sell.

With Agathas Web's managed hosting, support includes:

  • Operating system, runtime (PHP, Node, Python), database, and critical plugin updates, in a scheduled window and with staging tests before production.
  • Continuous monitoring (uptime, performance, errors, and logs) with Grafana, Prometheus, and Sentry, and alerts to the technical team's WhatsApp.
  • Cloudflare WAF with custom rules, fail2ban, rate limiting, and operating system hardening.
  • Daily and incremental backup, encrypted and off-server, with restoration tested monthly.
  • Response within 15 minutes for critical incidents, with SLA in the contract and a documented incident plan.
  • Direct support from those who operate your environment, without a Level 1 call center reading a script.

How it works: we start with a diagnosis of your current environment (versions, SAPI, workers, exposure). If migration makes sense, we perform the migration within 7 business days with a rollback plan. After that, alerts like this enter our support workflow: PHP2Shell mitigation (or the equivalent for the next flaw) in the interim until the patch, the update in a scheduled window, and verified worker restarts, without you needing to open a ticket. To hire us, speak with our team via WhatsApp on the managed hosting page and describe what you're running today. If your case involves an LMS, we also offer dedicated Moodle hosting.

Conclusion: Mitigate Today, Update Tomorrow, Verify Always

PHP2Shell mitigation is a tourniquet. It stops the bleeding for a few hours while you update to 8.5.12, 8.4.27, 8.3.36, or 8.2.35, restart **all** workers, and confirm via the web server that the new version is running. Those who stopped at `php.ini` are less exposed, but still exposed.

If you are still running PHP 8.1 or older, PHP2Shell is the push you needed: there will be no official release for these branches. And if your server relies on someone remembering to check security news, perhaps that's the real problem. Explore Agathas Web's managed hosting and leave the next emergency patch to those who operate servers every day.