FineShot.AI
•6 min read

PHP2Shell Explained: The Critical PHP Flaw Behind Emergency Patches (and How to Check You Are Safe)

On 21 October 2026 the PHP team shipped emergency patches for two critical flaws now known as PHP2Shell. This isn’t a bug in WordPress or in a plugin. It’s in PHP itself, the runtime underneath WordPress, Laravel, Drupal, Magento and most of the web. If your server runs PHP and answers web requests, this one is about you.

Here’s what PHP2Shell is, how to check whether you’re patched (it’s less obvious than it sounds), and what we did on our own server.

Watch the breakdown on YouTube

We covered PHP2Shell in two videos on our YouTube channel, @fineshotai:

  • Long-form video: the full walkthrough, from what PHP2Shell is to checking and patching a real Ubuntu server step by step. Watch on YouTube →
  • Short-form video: PHP2Shell explained in under a minute. Watch the Short →

What is PHP2Shell?

PHP2Shell is two memory-safety bugs in the PHP runtime, CVE-2026-109618 and CVE-2026-109619. PHP rates them 9.2 (critical) on CVSS v4. Both can lead to remote code execution without authentication. In other words, an attacker can run their own code on your server just by sending it requests.

Both come from PHP leaving memory in a bad state when a request ends abnormally:

  • CVE-2026-109618 (out-of-memory corruption): if PHP runs out of memory at the wrong moment, it can be interrupted while internal request data is only half set up. The cleanup code then treats that broken data as valid.
  • CVE-2026-109619 (stale state): some internal state belonging to one request can survive after its memory has been freed. The next request handled by the same PHP worker may use that stale state before it’s reset.

The scary part is where it happens. This is inside PHP’s own request handling, before your application code runs. Your WordPress plugins, your framework and your input validation don’t matter here. A fully up-to-date app on an unpatched PHP is still exposed.

Who is affected?

Every way of serving PHP on the web is in scope: PHP-FPM (the usual nginx setup), Apache mod_php, php-cgi, FrankenPHP and LiteSpeed. The PHP security team considers mod_php the highest risk.

PHP branchFixed upstream in
8.58.5.12
8.48.4.27
8.38.3.36
8.28.2.35
8.1 and olderEnd of life. No official release, but source backports exist and many Linux distributions ship their own fixes

Early reports claimed “every PHP version since PHP 5”. That wide range hasn’t been confirmed by an official advisory, but if you’re on an old, unsupported PHP you should assume you’re affected.

A messy disclosure

  • 17 Oct: Amazon’s honeypots record an exploitation attempt while the bugs are still under embargo.
  • 20 Oct: details leak online before the coordinated release.
  • 21 Oct: PHP ships the emergency releases. Linux distributions had patched packages ready.

Reports on how much it’s being exploited in the wild are still changing. Some security firms report attempts, others had seen nothing yet. Cloudflare has deployed WAF rules for the known attack patterns, including on free plans. The safe assumption is that exploitation is coming, if it hasn’t already.

The trap: “php -v” can lie to you

This is the part that catches people out. On our Ubuntu 24.04 server, php -v says PHP 8.3.6. The upstream fix is 8.3.36, so it looks badly vulnerable. It isn’t.

Ubuntu and Debian don’t bump the upstream version number. They backport the security fix into their own package and change only the package revision. So you need to check the package, not the PHP version:

# Which PHP package revision is installed?
dpkg -l | grep php8.3-fpm
#   ii  php8.3-fpm  8.3.6-0ubuntu0.24.04.13  ...

# Does it contain the PHP2Shell fix?
zcat /usr/share/doc/php8.3-common/changelog.Debian.gz | grep -m1 109618
#   - debian/patches/CVE-2026-109618_109619.patch: ...

If the changelog mentions CVE-2026-109618, the fix is installed. On RHEL, Alma or Rocky, check the package changelog with rpm -q --changelog php-fpm | grep 109618.

The second trap: installed is not running

PHP-FPM is a long-running service. Updating the package replaces the files on disk, but the workers already in memory keep running the old, vulnerable code until the service restarts. Check that the service started after the update:

# When was the package updated?
grep "upgrade php8.3-fpm" /var/log/dpkg.log | tail -1

# When did PHP-FPM last start?
systemctl show php8.3-fpm -p ActiveEnterTimestamp

# If the start time is older than the update:
sudo systemctl restart php8.3-fpm

Using Apache with mod_php? Restart Apache instead. Running PHP in Docker? Pull the patched base image and rebuild and redeploy. Restarting the old container isn’t enough.

How to patch

# Ubuntu / Debian
sudo apt update
sudo apt install --only-upgrade 'php8.3-*'
sudo systemctl restart php8.3-fpm

# Then confirm the web server is happy
sudo nginx -t && sudo systemctl reload nginx

Replace 8.3 with your version. If you installed PHP from a third-party repository, check that it has actually shipped the fix. Some volunteer-run repositories hadn’t on release day. If yours hasn’t, switch to your distribution’s packages.

Can’t patch right away?

  • PHP says no configuration change fully fixes this. Patching is the real fix.
  • Put the site behind a WAF that has PHP2Shell rules (Cloudflare’s are available on the free plan).
  • For anything that can’t be fixed, national CERTs advise taking it offline or putting it behind a VPN until it can be.
  • Watch for php-fpm, apache2 or httpd starting shells or tools like sh, bash, curl or wget. A web server process doing that is a strong sign of compromise.

What we found on our server

Our server runs several PHP sites (including this blog) on Ubuntu 24.04 with nginx and PHP-FPM 8.3. When we checked:

  • php -v showed 8.3.6, which looks vulnerable at first glance.
  • The installed package was 8.3.6-0ubuntu0.24.04.13, and its changelog includes the PHP2Shell patch. ✅
  • We had installed the update by hand (apt install --only-upgrade php8.3*) on the night of 21 October, the same day the fix shipped, and PHP-FPM restarted the next morning. So the patched code is the code that’s actually running. ✅

Patching on release day helped. But we only know we’re safe because we checked both the package and the running process afterwards. Do the same.

Checklist

  1. Find every server and container that runs PHP for the web.
  2. Check the package changelog for CVE-2026-109618, not just php -v.
  3. Update, then restart PHP-FPM / Apache or redeploy containers.
  4. Still on PHP 7 or 8.1? Plan the upgrade now. These branches no longer get official fixes.
  5. Turn on automatic security updates so the next one is handled overnight.

Sources and further reading: Help Net Security · BleepingComputer · The Hacker News · watchTowr FAQ


Prefer watching? Watch the full PHP2Shell walkthrough and the one-minute Short on youtube.com/@fineshotai, and subscribe for more hands-on server and security breakdowns.