PHP2Shell (CVE-2026-109618 / CVE-2026-109619): Check and Patch Your PHP Servers
PHP2Shell is a pair of unauthenticated remote code execution flaws in the PHP engine, CVE-2026-109618 and CVE-2026-109619, fixed on October 21, 2026 in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. Any web server running an earlier upstream build is exposed. Upgrade, restart PHP-FPM or Apache so the new code loads, and move off PHP 8.1 or older.
On October 21, 2026 the PHP project shipped fixes for two critical flaws in the PHP engine itself. Neither needs a login, and neither depends on a bug in your application code. If a server runs PHP and answers web requests, it is in scope until it is patched and restarted.
- Which PHP versions are affected and which release fixes each branch
- How to check your PHP version from outside and on the server
- Why a distribution package can be patched while reporting an older version
- What to do today if a server can't be patched yet
What PHP2Shell Is
Both flaws are rated 9.2 (CVSS v4.0) and allow code to run with the privileges of the web server's PHP worker. They sit in PHP's own request handling, so keeping your application and plugins up to date does not close them.
| CVE | Flaw | What It Allows |
|---|---|---|
| CVE-2026-109618 | Memory corruption when a request hits the memory limit mid-allocation | Remote code execution. On Apache with mod_php it can be triggered before any application code runs. |
| CVE-2026-109619 | Use-after-free: state from one request survives into the next request on the same worker | Remote code execution, worker crashes, and possible leakage of memory from earlier requests |
Every way of serving PHP on the web is in scope: Apache mod_php, PHP-FPM behind nginx or Apache, php-cgi, FrankenPHP and LiteSpeed. mod_php is the highest-risk setup because the attack path needs nothing from your application.
- The CVE IDs leaked on October 20, ahead of the scheduled release. Fixes shipped October 21.
- CISA has urged immediate patching and has not reported confirmed exploitation.
- Attack attempts against the flaws have been reported, and independent reproduction is under way. Treat a public exploit as imminent.
- Not yet listed in the CISA Known Exploited Vulnerabilities catalog.
Affected and Fixed Versions
| PHP Branch | Vulnerable | Fixed In |
|---|---|---|
| 8.5 | Below 8.5.12 | 8.5.12 |
| 8.4 | Below 8.4.27 | 8.4.27 |
| 8.3 | Below 8.3.36 | 8.3.36 |
| 8.2 | Below 8.2.35 | 8.2.35 |
| 8.1 and older | All releases | No routine fix. Upgrade to a supported branch. |
PHP 8.1 reached end of life on December 31, 2025. Limited source-level backports exist for some older branches, but no packaged release. For anything older than 8.2 the practical answer is the one in the EOL software playbook: upgrade, or take the system off the internet.
How to Check Your PHP Version
From Outside
Many servers announce their PHP version in the X-Powered-By response header. This is what an attacker's scanner reads first.
curl -sI https://www.example.com | grep -i x-powered-by # X-Powered-By: PHP/8.3.12 <- below 8.3.36, vulnerable
No header doesn't mean you're safe. It means the version is hidden, so confirm it on the host.
On the Server
Check the binary that actually serves web traffic. The command-line php and the PHP-FPM service are often different builds, and a server can run several PHP-FPM versions side by side.
php -v # CLI only php-fpm8.3 -v # Debian/Ubuntu FPM (one per installed version) php-fpm -v # RHEL/Fedora FPM ls /etc/php/ # every PHP version installed (Debian/Ubuntu)
Distribution Packages
Debian, Ubuntu, RHEL and their derivatives often patch a security flaw into the version they already ship rather than moving to the new upstream release. The server is fixed, but it still reports something like 8.2.29. Check the package changelog for the CVE ID before concluding either way.
# Debian / Ubuntu apt changelog php8.3-fpm | grep -E "CVE-2026-10961[89]" # RHEL / Alma / Rocky / Fedora rpm -q --changelog php-fpm | grep -E "CVE-2026-10961[89]"
Patch and Restart
- Update PHP from your distribution's security repository, or to the upstream fixed release for your branch.
- Restart every process that loaded PHP. A running PHP-FPM pool or Apache with mod_php keeps the old, vulnerable code in memory until it restarts.
- Re-check the version from the server and from outside, using the commands above.
- Check every host. Staging servers, old marketing sites and admin tools on separate subdomains run PHP too.
sudo systemctl restart php8.3-fpm # PHP-FPM sudo systemctl restart apache2 # Apache + mod_php (httpd on RHEL)
Some third-party package repositories and hosting control panels that compile PHP themselves did not have fixed builds on release day. If your PHP comes from one of them, confirm a fixed build exists before assuming the update went through.
If You Can't Patch Today
CISA's guidance is direct: if a PHP system can't be updated right away, or still runs PHP 8.1 or older, take it offline until it is. If that isn't possible, these steps narrow the window. None of them is a fix.
- Restrict reach: limit the site to known IP ranges or put it behind a VPN while you patch.
- WAF rules: a web application firewall may block known exploit patterns. Check that its rules have been updated for PHP2Shell.
- Upload progress tracking: setting
session.upload_progress.enabled = Offin php.ini has been reported to reduce exposure for some attack paths. Test it first, then restart PHP. - Watch the workers: alert on PHP or web-server processes that spawn shells, run download tools, or open outbound connections they normally wouldn't.
expose_php = Off removes the X-Powered-By header. Removing easy fingerprints is good practice, but automated attacks often skip the version check and try the exploit anyway.
How DriftAlarm Helps
DriftAlarm's external scans fingerprint the PHP version each of your hosts advertises. Any version below the PHP2Shell fix, and any end-of-life branch, is flagged as a critical finding with the fixed release named, and an alarm fires when a vulnerable version appears on your perimeter. Hosts that hide their version can't be confirmed from outside, so use the server-side checks above for those.
Related Security Guides
- EOL Software Playbook: what to do with PHP 8.1 and older, now that no routine fix is coming.
- The Patch Window Is Dead: why the gap between disclosure and exploitation keeps shrinking.
- WAF and Vulnerability Scanning: what a WAF does and doesn't hide while a fix is pending.
- Attack Surface Monitoring: finding the PHP hosts nobody remembered were public.
Summary: PHP2Shell Response Checklist
- List every internet-facing host that runs PHP, including staging and forgotten subdomains
- Check the web-serving PHP version and the package changelog on each
- Update to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (or the distribution's patched package)
- Restart PHP-FPM and Apache, then re-check the version
- Take PHP 8.1 and older hosts offline or restrict them until upgraded
- Review web and PHP-FPM logs for crashes and unusual child processes since October 20
- Set
expose_php = Offon hosts that still advertise their version - Put the internet-facing PHP inventory on a recurring check, not a one-off sweep
Frequently Asked Questions
How do I check which PHP version my website is running?
From outside, run curl -sI against the site and look for an X-Powered-By header such as PHP/8.3.12. On the server, check the binary that serves web traffic, not just the command line: php-fpm8.3 -v on Debian or Ubuntu, php-fpm -v on RHEL-family systems. The CLI and the FPM service are often different builds.
My Linux distribution still reports an older PHP version after updating. Am I still vulnerable?
Not necessarily. Debian, Ubuntu and RHEL-family distributions often backport security fixes into the version they already ship, so a patched server can still report something like 8.2.29. Check the package changelog for CVE-2026-109618 and CVE-2026-109619 with apt changelog or rpm -q --changelog. If the CVE IDs are listed and PHP has been restarted, the host is patched.
Is hiding the X-Powered-By header or disabling session.upload_progress enough?
No. Turning off expose_php only hides the version string, and automated attacks often try the exploit without checking it. Disabling session.upload_progress has been reported to reduce exposure for some attack paths, but neither the PHP project nor CISA presents it as a fix. Use these to narrow the window for a day or two while the real update and restart are scheduled.
What should I do if a server is still on PHP 8.1, 8.0 or 7.4?
Treat it as unpatched. Those branches are end-of-life and received no packaged release for PHP2Shell, only limited source backports. CISA advises taking PHP 8.1 and older off web-facing duty until upgraded. If that is impossible today, restrict access to known IP ranges or a VPN, set a hard date for the upgrade to a supported branch, and assign an owner.