Security Alert · PHP2Shell

Your Host Patched PHP2Shell. Did You Patch Your Dev Machine?

YOUR HOST $ php -v PHP 8.5.5 YOUR LAPTOP

If you run PHP anywhere outside a managed host — your laptop, a VPS, a Raspberry Pi, a Docker container — check it today. On October 21, 2026, PHP shipped emergency fixes for two critical flaws, CVE-2026-109618 and CVE-2026-109619, nicknamed PHP2Shell. Together they let an attacker run code on a server with no login, through any PHP page, before WordPress or your own code even loads.

The good news: most managed WordPress hosts patched their servers within about a day. My own sites were covered at the server level by the next evening.

The bad news: nobody patches your machine for you. The laptop running a local stack, the $5 VPS you set up last year, the Docker image you built and forgot — those stay vulnerable until you update them. That long tail is where the attacks will land over the next few months.

How big is this?

PHP is not a niche language. It runs most of the web, and WordPress sits on top of a huge share of it.

69.3%
of websites with a known server-side language run PHP
W3Techs, Oct 23, 2026
42.6%
of all websites run WordPress, which is built on PHP
W3Techs via Barn2, Apr 2026
22.6M
internet-facing instances flagged as potentially vulnerable
Palo Alto Networks via TechTarget, Oct 21, 2026
2.24M
servers openly advertising PHP in their headers
Shodan count via CybelAngel, Oct 20, 2026
59%
of those that show a version are on branches with no official fix coming
Shodan count via CybelAngel
34.6%
of PHP websites still run PHP 7 or PHP 5
W3Techs, Oct 23, 2026

And the machines nobody counts

Those numbers only cover servers you can see from the internet. Nobody counts the PHP installs on developer laptops, office PCs, and forgotten test boxes. Here’s a rough sense of scale: about 1 in 5 developers uses PHP (18.2% in Stack Overflow’s 2024 survey), and SlashData estimated 6.3 million PHP developers back in 2021. Most of them run at least one local stack — MAMP, XAMPP, WampServer, Homebrew, Docker, or Laravel Herd — and many run several.

That’s likely millions of unmanaged PHP installs that no hosting company will ever patch. That last part is my estimate, not a measured number, but it’s why I’m writing this.

Patched for you

  • Managed WordPress hosting
  • Shared and reseller hosting (cPanel, CloudLinux)
  • Managed VPS and dedicated servers

Patched by YOU

  • Your laptop: MAMP, XAMPP, WAMP, Homebrew, Herd
  • Self-managed VPS and Raspberry Pi
  • Docker images and AI-built dev servers

Which PHP versions are safe

You need PHP 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or newer. Anything older on those branches is vulnerable.

Your PHP branch Fixed in Notes
8.5 8.5.12 Current branch
8.4 8.4.27 Supported through 2028
8.3 8.3.36 Supported
8.2 8.2.35 End of life December 31, 2026
8.1, 8.0, 7.4 No official release Minimal source patches only; cPanel and CloudLinux backported fixes into their packages
7.3 and older None Upgrade or retire it
🔍

Version number looks old? Some hosts patch without changing it. CloudLinux put the fix into its existing builds, so a patched server can still say 8.4.26. Check the Build Date in phpinfo: anything built on or after October 21, 2026 has the fix.

Find every PHP you’re running

Most of us have more than one PHP and don’t realize it. Check each place it could live.

On a website or local server: phpinfo

  1. Create a file with a hard-to-guess name, like check-8x3k.php. Don’t call it info.php; bots look for that name.
  2. Put this one line in it:
    <?php phpinfo(); ?>
  3. Upload it to the site’s root folder (usually public_html), or drop it in your local web folder.
  4. Open it in your browser: yoursite.com/check-8x3k.php or localhost:8080/check-8x3k.php.
  5. Read three lines near the top: PHP Version (compare it to the table), Build Date (on or after Oct 21, 2026 = fixed), and Loaded Configuration File (tells you which PHP install it is).

Only need the number? Use <?php echo phpversion(); ?> instead. It reveals less.

On the command line

php -v
which -a php

which -a lists every PHP on your path. Two or three results means multiple installs, and each one needs updating.

⚠️

Check both. The command-line PHP and your web server’s PHP can be different. I updated PHP on my Mac, php -v said 8.5.12, and phpinfo still said 8.5.5 because Apache was holding the old version in memory.

Docker, VPS, and everything else

  • Docker: docker exec <container> php -v. Restarting a container does not update it. You need docker pull and a rebuild.
  • VPS or Raspberry Pi: SSH in, run php -v, update with apt or dnf, then restart Apache or PHP-FPM.
  • MAMP, XAMPP, Laravel Herd: these bundle their own PHP. Check for an app update.

Delete the phpinfo file when you’re done

The moment you’ve read the version, delete the file. A forgotten phpinfo page is a gift to attackers:

What it exposes

  • Your exact PHP version and build
  • Every setting, file path and module
  • The cookies of whoever views it. When I loaded mine while logged into WordPress, my login cookie was right there on the page.

How to delete it

  • cPanel: File Manager, select it, Delete
  • FTP / Dreamweaver: delete it on the remote server, then confirm the URL shows a 404
  • Mac: rm it from your web folder

If you viewed it while logged into WordPress and shared a screenshot or copy, log out and back in. That ends the session the cookie belonged to.

Updating PHP on a Mac (Homebrew)

If you installed PHP with Homebrew, this takes about five minutes. Run each command on its own line in Terminal.

  1. Update and upgrade PHP.
    brew update
    brew upgrade php

    You should see something like php 8.5.5 -> 8.5.12.

  2. See what Homebrew has running.
    brew services list
  3. Restart PHP and your web server (whatever shows as started).
    brew services restart php
    brew services restart httpd

    Use nginx instead of httpd if that’s what you run.

  4. Reload your phpinfo page. It should show the new version.

If phpinfo still shows the old version

This happened to me. The upgrade worked, but Apache showed error in brew services list and kept serving the old PHP from memory. Here’s the fix:

  1. Check Apache’s config is valid. It should say Syntax OK.
    /opt/homebrew/bin/httpd -t
  2. Check which PHP Apache loads.
    grep -n "libphp" /opt/homebrew/etc/httpd/httpd.conf

    If the path contains a version like Cellar/php/8.5.5, Apache is pinned to the old one. Change that line to the path that always points to the current version:

    LoadModule php_module /opt/homebrew/opt/php/lib/httpd/modules/libphp.so
  3. Kill the old Apache and start fresh.
    brew services stop httpd
    sudo apachectl stop
    pgrep -l httpd

    If pgrep still lists anything, run sudo killall httpd. Then:

    brew services start httpd
    brew services list

    Once httpd says started, reload phpinfo.

💡

Terminal tip: don’t paste commands with # comments on the end. The Mac’s Terminal passes them to brew as extra words, and you’ll get No available formula with the name "#".

Not using Homebrew?

  • MAMP: MAMP menu → Check for Updates. MAMP bundles its own PHP, so Homebrew won’t touch it.
  • Laravel Herd: open Herd, go to the PHP tab, and update.
  • Windows (WampServer / XAMPP): download the Thread Safe x64 build of the fixed version from windows.php.net, or update the whole stack.

Still running PHP 5 or 7 scripts? Now’s the time to move them

If you’ve been holding a server on PHP 7.x or even 5.x because an old script breaks on PHP 8, this is your wake-up call. PHP 7.3 and older got no fix at all for PHP2Shell. PHP 7.4, 8.0 and 8.1 only got minimal emergency patches. The next serious flaw may not get even that.

The good news: most old scripts break for the same handful of reasons, and they’re fixable in an afternoon.

What usually breaks

Old code Removed in Replace with
mysql_connect(), mysql_query() and other mysql_* PHP 7.0 mysqli or PDO with prepared statements
ereg(), eregi(), split() PHP 7.0 preg_match(), preg_split()
each() PHP 8.0 foreach
create_function() PHP 8.0 Anonymous functions: function() { ... }
$string{0} curly-brace offsets PHP 8.0 $string[0]
utf8_encode(), utf8_decode() Deprecated in 8.2 mb_convert_encoding()
Adding properties to objects on the fly Deprecated in 8.2 Declare the property in the class

PHP 8 is also stricter. Undefined variables and array keys throw warnings, passing the wrong type to built-in functions throws errors instead of quietly returning null, and 0 == "abc" is now false. Code that relied on PHP being forgiving will start complaining.

How to tackle it

  1. Scan before you change anything. PHPCompatibility checks your code against a target PHP version and lists every problem by file and line.
  2. Let a tool do the boring fixes. Rector rewrites a lot of old syntax automatically. Review its changes before you deploy.
  3. Swap mysql_* for prepared statements. Usually the biggest job, and it closes SQL injection holes at the same time.
  4. Test locally on PHP 8.4 or 8.5 with error reporting turned all the way up. Click every page and submit every form.
  5. Switch the live site in cPanel’s MultiPHP Manager only after it runs clean locally. Keep the old version handy for a day in case you need to roll back.
🤖

Let AI do the grunt work. Hand an AI coding assistant a file and ask it to modernize it for PHP 8.4 and explain each change. It’s tedious, pattern-based work they do well. Just test the result before it goes live.

Your 15-minute checklist

  • Ask your host if your server is patched, or check its status page
  • Run phpinfo on one live site; check Version and Build Date
  • Delete the phpinfo file
  • Run php -v and which -a php on your computer
  • Update every local PHP: Homebrew, MAMP, Herd, Docker
  • Restart your local web server and re-check phpinfo
  • Stop local servers and tunnels you aren’t using
  • Check any VPS or Raspberry Pi you’ve forgotten about
  • List scripts still on PHP 5 or 7 and schedule the upgrade
  • Bookmark your host’s status page for next time
Your host has your back on the server. Your own machines are on you.

Sources

SolarBlu
Scroll to Top