Skip to main content

Detect-PHP2ShellVulnerability

What It Does​

Finds every PHP installation on a Windows device and reports whether it is affected by PHP2Shell, two critical PHP vulnerabilities (CVE-2026-109618 and CVE-2026-109619). It can also update vulnerable installs to a patched PHP release.

PHP2Shell lets an attacker take control of a web server that runs an affected PHP version, without signing in. The website itself does not matter; the PHP version does. PHP fixed both vulnerabilities in versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35. PHP 8.1 and older no longer receive fixes.

By default, the script only reports and changes nothing. Each PHP installation it finds is listed with its location, its owner, its version, and whether it is vulnerable.


When to Use It​

  • You need to know which devices have PHP installed and whether it is vulnerable to PHP2Shell.
  • You need to find PHP that is bundled inside other products, not only PHP that was installed on purpose.
  • You want vulnerable standalone PHP installs patched automatically from NinjaOne, Datto RMM, ConnectWise RMM, or another RMM platform.

What You Need​

  • Windows 10, Windows 11, or Windows Server 2016 or later, 64-bit
  • The script running as SYSTEM or a local administrator through your RMM platform
  • Internet access to download the search tool and, when updating, the patched PHP release from PHP's official download site

PHP stored on network drives or on drives not formatted as NTFS is not found.


How It Works​

  1. Searches the device. Uses the Everything search tool to find every PHP program file on the device's NTFS drives in seconds. The tool is removed again afterwards, unless it was already installed.
  2. Identifies each installation. Reads the PHP version and build type, and works out who owns the installation:
    • Standalone: PHP installed on its own, for example from PHP's website, winget, or Chocolatey.
    • Stack: PHP that is part of a bundle such as XAMPP, WampServer, or Laragon.
    • Vendor: PHP that ships inside another company's product.
  3. Checks each version. Marks each installation as patched, vulnerable, end-of-life, or unknown.
  4. Updates vulnerable installs (optional). With FixLocalInstall, each vulnerable standalone install is updated to the latest patched release of its own PHP version line, for example from 8.3.30 to 8.3.36:
    • The patched release is downloaded from PHP's official site and checked for tampering before use.
    • IIS, services, and PHP processes that use the installation are stopped, and the installation is backed up.
    • PHP installed with winget for all users is updated through winget. If winget does not have the patched release yet, the script updates the files directly.
    • Your PHP settings (php.ini) and add-on extensions are kept.
    • The script confirms the updated PHP starts correctly. If it does not, the backup is restored.
    • IIS and the stopped services are started again.

Stack and vendor installations are reported but never changed, since replacing PHP inside another product can break it. End-of-life versions are also left unchanged, since moving to a newer PHP version line needs application testing first.

You'll know it worked when the installation's status shows Patched and its version matches or is newer than the fixed release for its version line.


Updates Cause Brief Downtime​

When FixLocalInstall updates a PHP installation that IIS uses, IIS restarts. Every website on that server is unavailable for a short time, not only the PHP sites. Services that use the installation also stop and start again.

Run FixLocalInstall on servers inside a maintenance window. Running the script without FixLocalInstall causes no downtime.


Parameters​

ParameterDefaultTypeDescription
FixLocalInstallFalseSwitchUpdates every vulnerable standalone PHP installation to the latest patched release of its version line. Restarts IIS when IIS uses the installation.

With no parameters, the script reports every PHP installation and changes nothing.


Results by Installation​

InstallationStatusResult with FixLocalInstall
PHP 8.2.35, 8.3.36, 8.4.27, 8.5.12, or newerPatchedNo changes.
Standalone PHP 8.2 to 8.5, below the fixed releaseVulnerableUpdated to the latest patched release.
Stack or vendor PHP 8.2 to 8.5, below the fixed releaseVulnerableNo changes. Update it through the owning product.
PHP 8.1 or olderEnd-of-lifeNo changes. Upgrade to PHP 8.2 or later after testing the application.
Version could not be readUnknownNo changes. Check the installation manually.

If an update fails, the run is reported as failed in your RMM platform, and the result shows the reason for each installation that failed.


What Each Result Shows​

FieldMeaning
PathFolder where PHP is installed.
NameThe owning product: PHP, the bundle name (such as XAMPP), or the vendor product.
PublisherThe company behind the owning product, when known.
IsNativeTrue for a standalone PHP installation, False when PHP belongs to another product.
InstallTypeStandalone, Stack, or Vendor.
ManagedByWinget when winget installed PHP, otherwise None.
VersionThe installed PHP version. After an update, the new version.
InIisTrue when IIS uses this installation.
RunningTrue when PHP from this folder is running.
StatusPatched, Vulnerable, EndOfLife, or Unknown.
RequiredVersionThe first patched release for this version line.
ActionWhat the script did: nothing, updated, skipped with the reason, or failed with the reason.

Usage Examples​

Example 1: Report every PHP installation​

.\Detect-PHP2ShellVulnerability.ps1

What happens:

  • Every PHP installation on the device is listed with its status.
  • Nothing is changed.

Example 2: Report only installations that need attention​

.\Detect-PHP2ShellVulnerability.ps1 | Where-Object -FilterScript { $_.Status -ne 'Patched' }

What happens:

  • Only vulnerable, end-of-life, and unknown installations are listed.
  • Nothing is changed.

Example 3: Report and update vulnerable installations​

.\Detect-PHP2ShellVulnerability.ps1 -FixLocalInstall

What happens:

  • Every PHP installation is listed.
  • Vulnerable standalone installations are updated, with a backup taken first.
  • IIS restarts if it uses an updated installation.

Note: Run this inside a maintenance window on servers that host websites.


Troubleshooting​

ProblemCauseSolution
No PHP is reported, but PHP is installedPHP is on a network drive or a drive that is not formatted as NTFS.Check that drive manually.
The search tool did not finish loadingThe device was too busy to build its file index within 60 seconds.Run the script again.
An installation is skipped as Stack or VendorPHP belongs to XAMPP, WampServer, or another product.Update the owning product, or take the system offline until its vendor releases a fix.
An installation is skipped as end-of-lifePHP 8.1 or older has no fix.Upgrade to PHP 8.2 or later after testing the application.
The update fails to downloadThe device cannot reach PHP's download site.Allow HTTPS to downloads.php.net and run again.
The update fails and the backup is restoredThe updated PHP did not start correctly.Check the error log for the reason. The original installation is back in place.
Winget still shows the old PHP versionPHP was installed with winget for one user only and was updated directly.No action needed. PHP itself is patched.
Chocolatey still shows the old PHP versionThe installation was updated directly.Run choco upgrade for the PHP package when convenient. PHP itself is patched.

Files and Logs​

FileLocation
Script log.\Detect-PHP2ShellVulnerability-log.txt
Error log.\Detect-PHP2ShellVulnerability-error.txt
Backups of updated installationsC:\ProgramData\_Automation\Script\Detect-PHP2ShellVulnerability\Backup\ (kept for manual rollback)

Learn More​


Changelog​

2026-10-22​

  • Initial version of the document.