PHP2Shell: what to patch today and how we help
On October 21, 2026 the PHP project shipped emergency releases for two vulnerabilities in the interpreter itself: CVE-2026-109618 and CVE-2026-109619, together known as PHP2Shell. Both are rated CVSS 9.2. Both let an unauthenticated attacker run commands on the server with a single HTTP request. The details leaked a day before the planned disclosure, and honeypot networks reported attacks in the wild on the day the patches came out. If you run anything on PHP, this is the one to drop everything for.
Short version. Update to PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35, restart every worker, rebuild every image. If you are on 8.1 or older, read on. If you want us to do it, here is what we do and here is the door. Running WordPress and not a developer? This page is for you.
What the two bugs do
CVE-2026-109618 lives in request initialization. A crafted application/x-www-form-urlencoded POST, in the published proof of concept one field name of roughly 3.5 MB, makes PHP run out of memory while it is still building the request. The hash table that holds the form data has already counted the new entry, so request shutdown treats a half-built entry as real data and ends up calling a function the attacker chose. It happens before a single line of your application runs.
CVE-2026-109619 is a use-after-free across requests. Some worker-wide state keeps pointing at memory that was freed when the previous request ended. If a fatal error interrupts cleanup, or a late diagnostic recreates the state, the next request handled by that worker follows a stale pointer. The confirmed path on PHP-FPM and mod_php goes through session.upload_progress, which is on by default and runs even if your code never calls session_start().
Two consequences follow. A login does not protect you, because the attack lands before authentication code exists. And a successful exploit can return a normal 200 response and leave the worker running, so a site that looks healthy proves nothing.
Who is affected
Every PHP that serves HTTP: Apache mod_php (PHP itself rates it the highest risk), PHP-FPM behind nginx or Apache, php-cgi, LiteSpeed, FrankenPHP, and the PHP baked into Docker images and appliances. WordPress, Laravel, Symfony, Magento, Drupal and hand-written apps are all equally exposed, because the flaw is in the interpreter, not the framework.
| Branch | Fixed release |
|---|---|
| PHP 8.5 | 8.5.12 |
| PHP 8.4 | 8.4.27 |
| PHP 8.3 | 8.3.36 |
| PHP 8.2 | 8.2.35 |
| PHP 8.1, 8.0, 7.4 | No official release. Minimal source backports from PHP, or your distribution's packages. |
| PHP 7.3 and older, including PHP 5 | No fix. Upgrade. |
Linux distributions received the patches ahead of the release, so on Debian, Ubuntu, RHEL and friends a normal package update is usually enough. Check the changelog rather than the version number: vendors backport without bumping it.
Stopgaps, and why they are only that
PHP's own advisory is blunt: no configuration change fully mitigates these vulnerabilities. If you cannot patch within the hour, these narrow the attack surface while you get there:
session.upload_progress.enabled = 0closes the confirmed CVE-2026-109619 path. On PHP 8.5 also setfatal_error_backtraces = 0. Both must be loaded before request parsing, so restart the workers.- Cap the request body at the reverse proxy or load balancer, including requests without a usable
Content-Length, and reject absurd form field names. Make sure the WAF actually inspects large bodies instead of truncating them. - Set
memory_limit = -1at the administrator level and enforce memory at the container or cgroup level instead. Do not useRLIMIT_ASorRLIMIT_DATA; they trigger exactly the failed allocation the bug depends on. - Take anything that cannot be patched off the public internet until it can.
What to look for in the logs
- PHP error log: memory exhaustion fatals reported as
Unknown on line 0. The location means the failure happened during request setup, before any script. Legitimate workloads can cause this too, so treat it as a lead, not proof. - Apache error log: child processes dying with signal 11. Failed exploit attempts segfault.
- Access logs and WAF: POST bodies of several megabytes, unusually long field names, null or control bytes in form values.
- Process activity: a web worker spawning a shell is the strongest signal there is. If you see it, assume compromise and rotate secrets.
How we help
PHP and WordPress have been part of our stack for over a decade, and the DevOps people who run the proxies and containers sit in the same team as the people who patch the code. For PHP2Shell we run a fixed sequence, one senior engineer owning the case end to end:
- Inventory. Every PHP that answers HTTP, including staging boxes and containers nobody remembers, compared against the fixed releases.
- Patch and restart. Packages, rebuilt images or a hosting-panel update, then every worker restarted and the running version verified.
- Compromise check. Logs read for the indicators above, workers checked for spawned shells, the document root scanned for web shells, secrets rotated if anything looks wrong.
- Harden and report. Proxy limits, WAF rules and the safe way to set upload progress and memory limits, plus a written plan for legacy PHP that has to be upgraded rather than patched.
You get a short written report at every step. Send us your hosting, the PHP version if you know it and what the site does, and we reply the same business day with an assessment and a fixed quote. Beyond this incident, our security services cover audits, patching, hardening and ongoing WordPress care.
Sources we worked from: the Datadog Security Labs analysis, the watchTowr FAQ and the PHP project's advisories. Check them for updates; this post describes what was known on October 23, 2026.