Is PHP Running on Your ColdFusion Server? How to Check, and Remove It

39 points by rmason 10 hours ago on hackernews | 33 comments

If you run ColdFusion or Lucee on a Windows server with IIS, and you've never installed PHP on purpose, this one's for you. There's a good chance PHP is on your server. It may be left behind by a control panel, a phpMyAdmin install from years ago, or your host's setup image. Here's how to find out in a few minutes with PowerShell, and how to remove it safely if nothing uses it.

I remember when I could go years without applying a security fix. Now it feels like I'm chasing something down every few weeks: a patch here, a mitigation there, a bot hammering a page that shouldn't exist. Such is life in the AI era, sigh. 

While I was signing in to my test blog the other day, the admin page refused me with a plain IIS error: 403 Forbidden, and a message saying multipart form-data requests were blocked by a PHP mitigation. My blogs are ColdFusion. They don't run a single line of PHP. So why was a PHP security rule stopping me from signing in?


What happened


The timing wasn't a coincidence. On October 21, 2026, PHP shipped emergency patches for two critical flaws that let an unauthenticated request run code on the server, nicknamed PHP2Shell. Every PHP setup that serves web requests was affected: PHP-FPM, Apache's mod_php, php-cgi, FrankenPHP and LiteSpeed. The fix is to install a new version of PHP (8.5.12, 8.4.27, 8.3.36 or 8.2.35).

My hosting company responded the same week with a web server security rule. The rule lived in IIS's server-wide URL Rewrite rules, so it applied to every site on the server and blocked every request whose content type was multipart/form-data, regardless of the address. That's the encoding a browser uses for any form that can upload a file, and plenty of forms use it even when they don't.

PHP's own advice doesn't include blocking those requests. It's to patch, and until then to turn off session.upload_progress.enabled and lower post_max_size. Several of the official mitigations concern how PHP handles uploads, so I can see why a host would reach for the biggest hammer. For a PHP site that's a blunt but understandable shield. For my ColdFusion sites it meant the admin sign-in form, every image upload and every file upload failed on all four sites at once. The rule matched every address, not just .php ones.

Once I'd scoped the rule to .php addresses (more on that below), everything worked again. Then I asked the obvious question: why is PHP on this server at all? The answer was a phpMyAdmin install I had asked for years ago to manage one MySQL database. It was still there, still in a site folder, and its login page was open to the whole internet. The host turned the blanket rule off once I told them PHP was no longer in use, and I went looking for anything else PHP had left behind.


Check 1: is IIS sending .php files to PHP?


IIS only runs PHP if a handler mapping tells it to. Open PowerShell as Administrator on the server:

Import-Module WebAdministration
Get-WebHandler -PSPath 'IIS:\Sites' | Where-Object { $_.path -like '*.php' } | Select-Object name, path, scriptProcessor

If it prints nothing, IIS doesn't run PHP. If it prints something like this, it does, for every site that inherits the server's settings:

name    path  scriptProcessor
----    ----  ---------------
FastCGI *.php C:\php\php-cgi.exe

Note the handler's name and the scriptProcessor path. You'll need both if you remove it.


Check 2: are there any PHP files in your sites?


PowerShell's Get-ChildItem -Recurse works, but on a server with years of uploaded images it can crawl for minutes. Windows' own dir is much faster. This counts the PHP files under your web root:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | Measure-Object | Select-Object Count

If the count isn't zero, this shows which folders they're in, busiest first:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | ForEach-Object { Split-Path $_ -Parent } | Group-Object | Sort-Object Count -Descending | Select-Object -First 25 Count, Name | Format-Table -AutoSize

Mine found about 4,500 files in two folders, both phpMyAdmin: one inside a site, and a second copy at the web root, which IIS's Default Web Site served to anyone who visited the server's bare IP address.

If you find PHP files you don't recognize, especially scattered through image or upload folders, or changed recently, stop and treat it as a possible break-in. Attackers love dropping small PHP "web shells" into upload folders. This lists the most recently changed ones:

cmd /c "dir C:\inetpub\wwwroot\*.php /s /b" 2>$null | Get-Item | Sort-Object LastWriteTime -Descending | Select-Object -First 15 LastWriteTime, Length, FullName | Format-Table -AutoSize

Check 3: is PHP installed or running?


Get-Process php* -ErrorAction SilentlyContinue | Select-Object Name, Id, StartTime
Test-Path C:\php

No php-cgi.exe process just means nothing has asked for a PHP page recently. IIS starts it on demand. The handler from Check 1 is what matters.


Check 4: what can the internet see?


From any computer, try the usual addresses on your own sites:

foreach ($path in "phpmyadmin/", "phpMyAdmin/", "pma/", "info.php") {
    $url = "https://www.mysite.com/$path"
    try { $r = Invoke-WebRequest $url -UseBasicParsing -TimeoutSec 15; "$($r.StatusCode) $url" }
    catch { "$($_.Exception.Response.StatusCode.value__) $url" }
}

Anything that answers 200 deserves a look. A phpMyAdmin login page facing the internet is a standing invitation: bots try passwords on it all day, and every attempt starts PHP and talks to your database.


Removing it safely


Do these in order, and back up first. Every step is reversible.

1. Back up IIS's configuration

IIS can snapshot its own configuration and restore it in one command:

& "$env:windir\System32\inetsrv\appcmd.exe" add backup "before-php-removal"

To undo everything below: appcmd.exe restore backup "before-php-removal".

2. Move phpMyAdmin (and any other PHP app) out of the web folders

Move, don't delete. Its configuration file may hold a database password, so keep it somewhere private for a few weeks in case something turns out to need it:

New-Item -ItemType Directory -Force C:\Temp\removed-php | Out-Null
Move-Item C:\inetpub\wwwroot\mysite\phpmyadmin C:\Temp\removed-php\phpmyadmin-mysite

If Move-Item complains that a file is in use, PHP has it open. iisreset /stop, move it, then iisreset /start. (Your sites are down for a few seconds.) And if it says "Could not find a part of the path", it's the destination folder that's missing, not the source. That one fooled me.

For managing MySQL afterwards, a desktop tool on the server over Remote Desktop, like HeidiSQL or MySQL Workbench, does everything phpMyAdmin did without a public login page.

3. Block .php at the door

IIS's request filtering can turn away a file extension before any handler sees it. Added at the server level, it covers every site:

Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/security/requestFiltering/fileExtensions' -Name '.' -Value @{ fileExtension = '.php'; allowed = 'false' }

Now any .php address gets "404 - the request filtering module is configured to deny the file extension", whether the file exists or not.

4. Remove the handler and the FastCGI entry

Use the handler name from Check 1 (mine was FastCGI) and the php-cgi.exe path:

Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/handlers' -Name '.' -AtElement @{ name = 'FastCGI' }
Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/fastCgi' -Name '.' -AtElement @{ fullPath = 'C:\php\php-cgi.exe' }

Run Check 1 again. It should print nothing.

5. Uninstall PHP, last

If PHP came from an installer, remove it under Apps > Installed apps. If it's just a folder like C:\php, rename it to C:\php-removed for a few weeks before deleting it. If anything complains, you'll know right away, and it's one rename to put back.

If PHP was installed by your host, ask them before step 5. Their own monitoring scripts are unlikely to need it, but it's their install.


If you need to keep a rule like this


Maybe you do run PHP somewhere, or your host wants their rule. Then scope it to PHP addresses instead of every address. The rule's <match url=".*" /> was the whole problem. This changes it to .php addresses only, leaving ColdFusion's forms alone (use the rule's own name):

Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "system.webServer/rewrite/globalRules/rule[@name='PHP Mitigation']/match" -Name url -Value '\.php($|/)'

Note the single quotes around the pattern. I first tried the same change with appcmd.exe, and PowerShell quietly mangled the quoting: no error, and no change either. Set-WebConfigurationProperty with single quotes did it on the first try. Check the result with Select-String on C:\Windows\System32\inetsrv\config\applicationHost.config.


Lucee on Linux and Apache


The same questions, different commands:

php -v                          ## is the PHP command-line installed?
apachectl -M | grep -i php      ## is Apache running PHP (php_module, proxy_fcgi to php-fpm)?
find /var/www /home -name "*.php" 2>/dev/null | head -50

On Debian and Ubuntu, sudo a2dismod php8.3 (your version) and sudo systemctl restart apache2 stop Apache from running PHP. Then remove the packages with your package manager once you're sure nothing needs them. Control panels such as Virtualmin often install PHP for their own tools, so check before uninstalling.


Gotchas


  • A server-wide rule catches every site. A rule written for PHP blocked my ColdFusion sign-ins and uploads. If a 403 appears out of nowhere, read the full IIS error page; mine named the rule.
  • Hosts re-run their scripts. Mine recreated its rule on every run, so a local fix could have been undone silently. Tell your host what you changed and why.
  • A config edit can land in the wrong web.config. My first fix went into a site's web.config, and nothing changed. A quick Select-String on the file IIS actually reads would have saved me ten minutes.
  • Trusted Cache hides your fixes. If you replace a .cfm by hand while diagnosing, ColdFusion keeps running the old compiled copy until you clear it. A brand-new file name is the quick workaround.
  • Removing PHP isn't a substitute for patching. If you do run PHP, update it now to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 (or newer), and set session.upload_progress.enabled = 0 in php.ini until you can. PHP 8.1 and older no longer get updates from the PHP project. Removing PHP is only the right answer when nothing uses it.

Further Reading


This entry was posted on October 23, 2026 at 11:39 PM and has received 9491 views.

There are 0 comments.