November 2, 2026
PHP2Shell mitigation: reduce risk before patching CVE-2026–109618 and CVE-2026–109619
Can’t patch PHP yet? Step-by-step mitigations from proxy limits to virtual patching, plus IOCs and cleanup steps.
By CyberAlpaca
6 min read
CISA has urged organizations to patch PHP2Shell immediately. The name covers two critical PHP flaws, CVE-2026–109618 and its sibling CVE-2026–109619, and CISA added both to its Known Exploited Vulnerabilities catalog on October 26, 2026. Patching the PHP binary is the only real fix. But production schedules, vendor-pinned runtimes, and frozen container images mean many teams can't upgrade today. This advisory covers what reduces risk in the gap, what doesn't, and how to check whether anyone got in before you closed it.
The short version. If you can't patch today:
- Find every PHP runtime you expose, starting with Apache mod_php.
- Take the riskiest systems off the public internet, or put them behind a proxy.
- Cap request size and multipart parts at the proxy.
- Add WAF virtual patches for both CVEs.
- Apply PHP's configuration workarounds.
- Hunt for signs of compromise in logs going back to October 17, 2026.
Why can't PHP2Shell be fixed with configuration alone?
NVD rates CVE-2026–109618 critical (CVSS 3.1 score 9.8). When PHP hits an out-of-memory condition, its longjmp() error handling can leave request memory uninitialized, and attackers can chain that memory corruption into unauthenticated remote code execution (RCE). CVE-2026-109619 is a use after free: state from one request survives on the worker and the next request reads it.
The practical consequences matter more than the mechanics:
- No credentials needed. The attacker only needs network reach to a PHP endpoint and a crafted HTTP request pattern.
- Worker reuse widens the blast radius. Long-lived PHP-FPM or mod_php workers handle many requests, so stale state from a failed request can affect the next one.
- Application checks run too late. With mod_php, the corruption happens while PHP parses the request body, before your framework validates anything, and multipart/form-data gives attackers plenty of room to obfuscate.
PHP's own advisory says updating is the only complete mitigation. Everything below shrinks exposure; none of it removes the bug.
Why can't many teams patch PHP today?
- PHP 8.2, 8.3, 8.4 and 8.5 have fixed releases: 8.2.35, 8.3.36, 8.4.27 and 8.5.12.
- PHP 7.4, 8.0 and 8.1 only get minimal source backports from the PHP security team.
- PHP 5.4 to 7.3 get nothing from the PHP project: a vendor backport or a major upgrade.
That leaves roughly 48% of PHP sites with no full official release to upgrade to (W3Techs data). Distributions also backport the fix without changing the version number, so check NVD and your vendor's advisory, and look for the CVE in the package changelog rather than trusting the version string.
How do I protect PHP servers I can't upgrade right away?
Step 1: Find every PHP runtime you expose
CISA warns that PHP often hides inside other products. Start with internet-facing systems, and among those with Apache mod_php, which PHP considers the highest-risk setup. PHP-FPM, php-cgi, FrankenPHP and LiteSpeed are affected too. Check settings in a request served by the web server: the PHP command line often reads a different php.ini.
Step 2: Take the riskiest systems off the public internet
CISA's advice for systems you can't update, or that run PHP 8.1 or older, is to take them offline until they're patched. If you can't, restrict who reaches PHP (VPN, IP allowlist) and put a reverse proxy in front. Lock the origin to that proxy: steps 3 and 4 run there, and an attacker who reaches PHP directly skips them.
Step 3: Set request limits at the reverse proxy
PHP's advisory asks you to cap the decoded request size at the frontend, including requests without a Content-Length, to bound multipart parts and input variables, and to block multipart/form-data entirely where the application doesn't need it. Most public exploits start with a multipart request, so this is the strongest proxy control you have. In nginx (Sansec also gives the Apache version):
if ($http_content_type ~* "multipart/form-data") {
return 403;
}if ($http_content_type ~* "multipart/form-data") {
return 403;
}This breaks file uploads and some forms, so test the ones that matter. Researchers also reached the bug with large URL-encoded POSTs, so keep client_max_body_size in line with a low post_max_size (step 5). Size alone won't stop the multipart variants: public exploits fit about 900 parts into less than 1 MB (Datadog Security Labs). Counting parts and nesting is a job for a WAF rule.
Step 4: Add virtual patches for both CVEs
A virtual patch is a WAF rule that blocks a known exploit request before it reaches the vulnerable software. CISA notes that a WAF "may provide some protection until systems are updated or patched."
CrowdSec publishes two free virtual patches:
- vpatch-CVE-2026–109618 blocks multipart field names nested 12 levels or deeper, and bodies with more than 50 file parts.
- vpatch-CVE-2026–109619 blocks multipart requests carrying a
PHP_SESSION_UPLOAD_PROGRESSfield.
They run in the open-source CrowdSec WAF, with a bouncer in NGINX, OpenResty, Apache, HAProxy, Envoy or Traefik (install guide, WAF quickstart). Refresh the Hub index first: an older index installs the collection without the two rules.
sudo cscli hub update
sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules
sudo systemctl reload crowdsec
sudo cscli appsec-rules list | grep CVE-2026-10961sudo cscli hub update
sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules
sudo systemctl reload crowdsec
sudo cscli appsec-rules list | grep CVE-2026-10961Already running the CrowdSec WAF? Run sudo cscli hub update && sudo cscli hub upgrade, then reload.
The limits: forms nested 12 levels deep (some Drupal setups) or uploads of more than 50 files get blocked, as does PHP's session upload progress feature. A renamed session.upload_progress.name isn't covered. And the WAF only sees traffic that goes through it.
Step 5: Apply PHP's configuration workarounds
From PHP's advisories and CERT-EU, a last layer that doesn't fully protect you:
memory_limit=-1removes the predictable memory limit the confirmed exploit uses. One request can then use all server memory, so add a container or cgroup memory limit.post_max_sizeat 8M without uploads, 32M with them, and a lowermax_input_nesting_level.session.upload_progress.enabled=0, andfatal_error_backtraces=0on PHP 8.5.pm.max_requests=1if performance allows, so no FPM worker serves a second request.
Set them administratively (php_admin_value in every FPM pool, php.ini for mod_php), then restart every worker.
What doesn't reduce PHP2Shell risk?
- Hiding errors with
error_reporting, @ ordisplay_errors: PHP reads the stale state before it decides whether to report anything. ini_set()and.user.ini, which apply too late.RLIMIT_ASorRLIMIT_DATA, which trigger the vulnerable path.- Anything written in PHP: framework authentication and security plugins run after the request is parsed.
- Waiting for crashes. In Datadog's refined exploit, the request returns HTTP 200 and the worker keeps running.
How do I check whether PHP2Shell was exploited on my servers?
Start your review on October 17, 2026, when AWS saw the first attempts, four days before disclosure (via Datadog). CrowdSec's network recorded 450+ proven PHP2Shell attackers in the first 24 hours of observed exploitation, and the Live Exploit Tracker follows the activity since. No single signal proves an attack, so correlate these (Datadog):
- Requests: multipart bodies with
PHP_SESSION_UPLOAD_PROGRESSandPHPSESSIDfields your app doesn't use, hundreds of parts or names likefiles[R00001][a][a][a], upload filenames containing<?phpor|O:, andSet-Cookie: PHPSESSID=values that are unusually long or binary (the memory-leak stage). - Logs:
Allowed memory size of ... bytes exhausted ... in Unknown on line 0(PHP failed before any script ran), ApacheAH00052 ... Segmentation fault, and two to four memory errors on one worker followed by silence. - Host: a web worker (
www-data,apache) spawningsh,bashor download tools. Datadog calls it the most direct evidence of exploitation.
grep -E "exhausted .* in Unknown on line 0" /var/log/php*fpm*.log /var/log/apache2/error.log
sudo cscli alerts list | grep CVE-2026-10961grep -E "exhausted .* in Unknown on line 0" /var/log/php*fpm*.log /var/log/apache2/error.log
sudo cscli alerts list | grep CVE-2026-10961The second command lists attempts the CrowdSec WAF blocked. A clean log isn't proof of safety: a failure can happen before PHP writes anything.
What should I do if I find signs of compromise?
Follow the order of CISA's forensic triage steps, which its KEV entry points to:
- Preserve evidence first: memory, processes and connections, then logs. Patching or restarting workers destroys artifacts.
- Contain quietly: isolate the host without tipping off the attacker.
- Patch and replace: update PHP, rebuild images, restart every worker.
- Hunt and rotate: look for web shells and files you didn't deploy, then rotate every secret the web user could read.
- Escalate to full incident response if you confirm code execution, and keep monitoring after the fix.
FAQ
Does a WAF stop PHP2Shell, or do I have to patch PHP?
You have to patch PHP. Virtual patches block the request patterns the known exploits use and buy time, but they don't remove the bug and can't protect a server attackers reach directly.
Is PHP2Shell being exploited in the wild?
Yes. CISA added CVE-2026–109618 and CVE-2026–109619 to its KEV catalog on October 26, 2026, and CrowdSec's network recorded 450+ proven PHP2Shell attackers in the first 24 hours of observed exploitation. The IPs are tracked in the Live Exploit Tracker and collected in CrowdSec's paid PHP2Shell Attackers blocklist (contact CrowdSec for access).
Which PHP versions fix PHP2Shell?
PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12 fix both CVEs. Older branches depend on your vendor's backport, which may keep the old version number.
How do I protect an old PHP version, or a Docker image I can't rebuild?
Put a WAF on the reverse proxy in front: it inspects requests before they reach PHP, whatever the version or image behind it. It's a stopgap. Plan the migration or the rebuild while the rules hold the door.
Sources
PHP advisory for CVE-2026–109618 and for CVE-2026–109619; NVD (as of October 28, 2026); CISA alert and KEV catalog; CERT-EU 2026–018; Datadog Security Labs; Sansec.
Originally published on crowdsec.net.