What happened
On October 21, the PHP project shipped fixes for two vulnerabilities, CVE-2026-109618 and CVE-2026-109619. Both are rated CVSS 9.2 and, according to Arctic Wolf's write-up, can let an unauthenticated attacker run code on a server that is handling web requests with PHP.
The bugs live in PHP's own request-handling lifecycle, not in a framework or plugin:
- CVE-2026-109618 is memory corruption triggered when an out-of-memory condition interrupts PHP while request data is only partly set up.
- CVE-2026-109619 is a use-after-free: state belonging to one request can survive and be read by a later request on the same worker, which can also leak memory contents.
That second point is worth pausing on. Qualys notes that leaked worker memory can contain passwords, tokens and API keys. So even if nobody gets a shell on your box, secrets can walk out the door.
Things moved fast after the patch, and the scale is large: The Hacker News cites Censys estimates of more than 32 million PHP services still running an affected version.
- Amazon's threat intelligence team said targeting started four days before the fixes were published, as BleepingComputer reports.
- On October 24, a researcher at Perplexity confirmed successful code execution against honeypots (The Hacker News).
- On October 26, CISA added both CVEs to its Known Exploited Vulnerabilities catalog and gave US federal agencies until October 29 to fix them.
Why this is relevant even for small apps
Attackers don't pick targets by company size here. They scan the internet for anything that answers like PHP and try the exploit. A forgotten side project on a VPS is just as reachable as a big e-commerce site.
A few details make this one especially worth acting on:
- It doesn't depend on your code. Arctic Wolf points out that because the flaws are in PHP's request processing, exposure doesn't depend on which application you run. A perfectly written Laravel app on an old PHP build is still exposed.
- Many server setups are in scope. Apache with mod_php is considered the highest risk, but PHP-FPM, php-cgi, FrankenPHP and LiteSpeed are all named as affected, as are products and appliances that bundle PHP.
- Old PHP is common. Qualys reports that about 71% of the PHP installations it could version were already end-of-life. If you're on 8.1 or older, there's no regular upstream fix for you.
How to check your app
You're looking for one answer per server: is something serving web requests with PHP, and which exact version?
1. List everything you host. Not only the main app. Include marketing sites, blogs, docs, staging environments, admin tools and anything on a subdomain. The forgotten ones are the dangerous ones.
2. Look at response headers. Many PHP setups announce themselves in an X-Powered-By or Server header. No header doesn't mean no PHP (it can be turned off with expose_php = Off), but a header is a quick yes. Verbose error pages are another giveaway: a PHP stack trace in production tells an attacker exactly what you run.
curl -sI https://your-site.example | grep -i -E 'x-powered-by|server'
# X-Powered-By: PHP/8.3.20 <- PHP, and an old patch levelVerbose error pages and stack traces: how to turn them off3. Check the version that serves web traffic, not just the CLI. php -v on the server can report a different build than the one Apache or PHP-FPM actually uses; Qualys calls this out specifically. Check the FPM binary or your web server's PHP module, or ask your host.
php-fpm8.3 -v # or php-fpm -v, depending on your distro
apache2ctl -M | grep php # is mod_php loaded?4. Compare against the fixed versions. If you install PHP from your Linux distribution, the fix may be backported into a package with an older-looking version number, so check your distro's advisory rather than the version string alone. Otherwise you need at least:
- PHP 8.5: 8.5.12
- PHP 8.4: 8.4.27
- PHP 8.3: 8.3.36
- PHP 8.2: 8.2.35
5. Managed hosting? If you're on a managed WordPress host or a PaaS, check their status page or changelog for a PHP2Shell notice. Most will patch for you, but "most" isn't "all", and a self-managed VPS is entirely on you.
How to fix it
Patch, then restart. Updating PHP is the only complete fix.
The restart matters: running workers keep the old code in memory until they're replaced. For Docker, rebuild on an updated base image (for example a current php:8.3-fpm tag) and redeploy. Don't just restart the old container.
On Debian or Ubuntu with a PHP-FPM setup, it usually looks something like this:
sudo apt update && sudo apt install --only-upgrade 'php8.3*'
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2 # if you use mod_phpIf you can't patch today, Qualys summarizes PHP's interim mitigations. They reduce risk but don't make an unpatched server safe. Set them in php.ini or the FPM pool config (not .user.ini or ini_set), then restart all workers.
If a service is unpatched and doesn't need to be public, put it behind a VPN or IP allowlist, or take it offline until you can update.
; php.ini or FPM pool config (not .user.ini or ini_set)
session.upload_progress.enabled = 0
post_max_size = 8M ; 32M if you need uploads
upload_max_filesize = 6M ; keep below post_max_sizeOn PHP 8.1 or older, plan the upgrade now. Limited backports exist for some old branches, but you're relying on luck every time something like this lands.
Look for signs of compromise. Check for unexpected processes, new files in web roots, unfamiliar cron jobs and outbound connections from the web server. Arctic Wolf also notes that many "PHP2Shell" requests in logs reuse older techniques, so a scary-looking log line doesn't automatically mean a successful break-in.
Rotate secrets if you were exposed. Because CVE-2026-109619 can leak worker memory, treat secrets that passed through an unpatched, internet-facing PHP process as potentially seen. That means database passwords, API keys, session signing keys and payment provider keys. Laravel and similar frameworks keep these in .env, so also confirm that file was never web-accessible in the first place.
Quick checklist
Run through this for every domain you own:
- Every domain and subdomain you own is listed, including old marketing and staging sites.
- You know which ones run PHP, and the exact web-serving version.
- Each one is on 8.5.12, 8.4.27, 8.3.36, 8.2.35 or a vendor-patched build.
- PHP workers and web servers were restarted after updating.
- Anything unpatched is restricted or offline, with mitigations applied.
- Secrets on exposed hosts have been rotated.
- Production no longer advertises its PHP version or shows stack traces.
The bigger lesson
PHP2Shell will be patched and forgotten within a few weeks. The pattern won't. The gap between "fix published" and "being exploited" is now days, sometimes negative. Small teams can't out-run that with heroics. What works is knowing what you run and noticing quickly when something about it changes.
That's the same thinking behind our launch checklist for AI-built apps: most real-world incidents come from things that are easy to check, if you actually check them.
AppSafe scans your live site from the outside, the way an attacker would see it. It looks for issues like missing security headers, an X-Powered-By header that leaks your stack, exposed files and verbose errors, and gives you plain-language fixes. After you've patched, run a free scan on each of your domains to catch the other easy wins while you're in there.
