PHP2Shell: How One Request Became RCE, and the Fix
PHP2Shell is the nickname for two critical PHP runtime flaws, CVE-2026-109618 and CVE-2026-109619, disclosed in October 2026. Together they let an attacker run commands on a web server with one malformed request and no login. Exploitation started on 17 October, four days before PHP shipped fixes on 21 October.
This post walks the attack chain, the response that actually closes it, and the cleanup that patching alone never does. Everything here mirrors our free PHP2Shell RCE exercise, where you play both the attacker and the engineer on call.
What is PHP2Shell?
Section titled “What is PHP2Shell?”PHP2Shell is a pair of unauthenticated remote code execution (RCE) vulnerabilities in the PHP runtime itself, not in any framework or plugin. A crafted request corrupts how PHP sets up and tears down per-request data, so the runtime reuses memory from a half-finished request. That is enough to steer execution and run attacker-chosen commands as the web server user.
Because the bug sits below the application, every .php URL on an exposed server is a valid target. There is no account to phish, no upload form to abuse, and no vulnerable plugin to find.
How does a PHP2Shell attack work?
Section titled “How does a PHP2Shell attack work?”PHP2Shell exploitation is opportunistic, not targeted. Attackers mass-scan the internet for servers on a vulnerable build and work through whatever answers. The chain in the exercise has four short stages.
- Fingerprint. A plain
GETreturns headers likeServer: Apache/2.4.58andX-Powered-By: PHP/8.4.26. The fixed 8.4 build is 8.4.27, so the attacker knows the host is open. - Fire. One malformed request to any PHP page returns the output of a command the attacker picked.
- Loot. The same request reads the database password from the app config and counts the customer table, ready to exfiltrate.
- Persist. A small web shell lands at a harmless-looking path, such as a media cache folder, so access survives a restart and even a later patch.
Apache with mod_php is the worst case. The vulnerable request handling runs inside the web server process before any application code, so nothing in your app gets a chance to say no.
Is a WAF rule enough to stop PHP2Shell?
Section titled “Is a WAF rule enough to stop PHP2Shell?”No. WAF signatures are worth enabling, but a rule only blocks the request shapes it knows about. Attackers vary the payload until one gets through.
Treat the WAF as time you buy to patch. The flaw is in the runtime, so only a fixed runtime closes it.
How do you fix PHP2Shell?
Section titled “How do you fix PHP2Shell?”The fix has two parts, and teams under pressure routinely skip the second one.
- Update the runtime to a patched build (8.4.27 on the 8.4 branch, or your distribution’s backported package).
- Restart the service that holds PHP in memory: Apache for
mod_php, or PHP-FPM behind Nginx. Until it restarts, every request is still served by the old, vulnerable build.
A server that installed the package but never restarted reports a reassuring version in the package manager and stays exploitable. After the restart, check the live version the web server actually reports, then replay a known-bad request and confirm it now fails. Our OS updates and patching basics exercise drills the same “installed is not running” habit for workstations.
What should you clean up after patching a PHP RCE?
Section titled “What should you clean up after patching a PHP RCE?”Patching closes the door. It does nothing about what came through it while the door was open, and with PHP2Shell the door was open before a patch existed. Assume any server exposed before you patched was reached.
- Hunt for planted files. Look for PHP files your deploy never shipped, especially in writable folders like uploads, caches and temp directories. Remove the web shell.
- Rotate every secret the server could read. Database passwords, API keys and cloud credentials in config files or environment variables are all burned.
- Route possible data exposure. If the attacker could reach personal data, hand it to your data protection team now. Under GDPR the 72-hour notification clock starts when you become aware of a breach, not when the investigation ends.
Reporting quickly matters as much as the technical fix. Our incident reporting exercise in the Security Awareness catalogue covers who to tell and what to record.
Where else is PHP running in your environment?
Section titled “Where else is PHP running in your environment?”The public storefront is rarely the only copy. A runtime zero-day exposes every install at once, including ones a single package update never touches.
- Containers built from a base image that pinned the old PHP. Rebuild from an updated image and redeploy; patching a running container is lost on the next restart.
- Appliances, control panels and vendor products that bundle their own PHP. These wait on the vendor’s update.
- Forgotten staging hosts, internal tools and marketing microsites.
This is the same problem as any component with known vulnerabilities: you cannot patch what you have not inventoried. If you build container images, the vulnerable base images exercise shows how an old runtime hides inside a layer you never look at.
Why train on real incidents like PHP2Shell?
Section titled “Why train on real incidents like PHP2Shell?”Runtime zero-days follow the same shape every time: one unauthenticated request, every exposed server at once, a patch that arrives mid-exploitation. Engineers who have rehearsed update, restart, verify, clean up and report make fewer mistakes when the real alert fires at 2 a.m.
The Real-World Incidents catalogue turns breaches like this one into hands-on exercises, alongside the MGM Resorts breach walkthrough. Developers who want the code side can continue with command injection, and our roundup of the best secure coding training platforms compares the wider options.
Want your platform team drilled on the next runtime zero-day before it lands? Talk to us about rolling out incident-based training.