Back to blog
AzureBest PracticesCloud SecurityOperations & ComplianceServerless

Azure App Service Running Outdated PHP: Risks and How to Fix It

Learn why running an outdated PHP runtime on Azure App Service is a security risk, how to upgrade safely with deployment slots, and how to enforce supported versions.

TL;DR

This check flags Azure App Services running an end-of-life PHP runtime, which exposes your app to unpatched vulnerabilities and broken dependencies. Upgrade to a supported PHP version with az webapp config set --php-version and pin the version in your IaC.

PHP still powers a huge slice of the web, from WordPress installs to custom Laravel APIs. When you run those workloads on Azure App Service, the platform manages the PHP runtime for you. That convenience cuts both ways: it is easy to deploy an app once and never think about the runtime again, right up until the version you depend on hits end of life and stops getting security patches.

The appservice_oldphp check looks at your App Service configuration and tells you when the PHP runtime is older than a currently supported release. It is a small detail that tends to rot quietly in the background, which is exactly why it deserves attention.


What this check detects

The check inspects the runtime stack configured on each Azure App Service (specifically Linux App Services using PHP, and the legacy phpVersion setting on Windows plans). It compares the configured PHP version against the versions Microsoft and the PHP project still support, and raises a finding when the runtime is past its support window.

Concretely, a finding means one of the following is true:

  • The App Service is pinned to a PHP version that PHP.net no longer maintains (no security or bug fixes).
  • The version is on the Azure deprecation list and scheduled for removal from the platform.
  • The runtime is several minor versions behind the latest supported branch.

Note: Azure App Service on Linux uses container-based runtimes, so the PHP version maps to a specific base image (for example PHP|8.3). On Windows plans, PHP was historically set through the phpVersion site config property, but Microsoft has deprecated built-in PHP on Windows. New PHP workloads should run on Linux.


Why it matters

An outdated PHP runtime is not a cosmetic problem. It directly widens your attack surface and creates operational drag.

Unpatched security vulnerabilities

Once a PHP branch reaches end of life, the PHP project stops shipping fixes for it, including security fixes. Real CVEs land against PHP regularly, covering things like heap buffer overflows in the core, issues in the libxml and gd extensions, and request smuggling in FPM. If you are on PHP 7.4 (EOL since November 2022) or PHP 8.0 (EOL since November 2023), any vulnerability disclosed after those dates is permanently open on your runtime. Attackers actively scan for old PHP fingerprints because the exploit work is already done for them.

Compliance findings

Running unsupported software fails common controls in PCI DSS, SOC 2, and ISO 27001. Auditors treat an EOL runtime as a known unpatched component, and that single finding can cascade into a broader remediation requirement across your estate.

Dependency breakage and stalled upgrades

The longer you sit on an old runtime, the harder the eventual jump becomes. Composer packages drop support for old PHP versions, framework LTS windows close, and you end up forced into a high-risk multi-version leap under pressure instead of a routine step.

Warning: Azure periodically retires deprecated runtimes from the platform entirely. When that happens, affected apps can stop starting after a restart or a redeploy. An EOL runtime is not just insecure, it is on a clock toward an outage you did not schedule.


How to fix it

The fix is to move the App Service to a supported PHP version. Always test against the target version in a non-production slot first, because minor and major PHP bumps can introduce breaking changes in deprecated functions and stricter type handling.

1. Check the current version

az webapp config show \
  --resource-group my-rg \
  --name my-php-app \
  --query "linuxFxVersion" \
  --output tsv

This returns something like PHP|7.4. For older Windows plans, query phpVersion instead:

az webapp config show \
  --resource-group my-rg \
  --name my-php-app \
  --query "phpVersion" \
  --output tsv

2. List supported runtime versions

az webapp list-runtimes --os-type linux | grep -i php

Pick the newest version your application supports. As of writing, PHP 8.3 and 8.4 are the actively maintained branches.

3. Update the runtime in a staging slot

Danger: Changing the runtime on a live production App Service triggers a restart and can break the app if your code is not compatible with the new PHP version. Do this in a deployment slot first, validate, then swap.

# Create a staging slot
az webapp deployment slot create \
  --resource-group my-rg \
  --name my-php-app \
  --slot staging

# Set the new PHP runtime on the slot
az webapp config set \
  --resource-group my-rg \
  --name my-php-app \
  --slot staging \
  --linux-fx-version "PHP|8.3"

4. Validate, then swap into production

Run your smoke tests against the staging slot URL. Watch the logs while you do it:

az webapp log tail \
  --resource-group my-rg \
  --name my-php-app \
  --slot staging

Once the app behaves correctly, swap the slot into production. The swap is near-instant and gives you a fast rollback path by swapping back.

az webapp deployment slot swap \
  --resource-group my-rg \
  --name my-php-app \
  --slot staging \
  --target-slot production

Fixing it without slots

If the plan tier does not support slots, set the version directly. Expect a restart.

az webapp config set \
  --resource-group my-rg \
  --name my-php-app \
  --linux-fx-version "PHP|8.3"

Tip: Deployment slots are available on Standard tier and above. If you are on Basic and managing a production PHP app, the cost of bumping to Standard is usually worth it just for the zero-downtime swap and rollback capability during runtime upgrades.


How to prevent it from happening again

A one-time fix does not stop the same drift from recurring next year. Pin the version in code and enforce it.

Define the runtime in IaC

With Terraform, set php_version explicitly on the site config so the runtime is reviewed in every pull request:

resource "azurerm_linux_web_app" "php_app" {
  name                = "my-php-app"
  resource_group_name = azurerm_resource_group.rg.name
  location            = azurerm_resource_group.rg.location
  service_plan_id     = azurerm_service_plan.plan.id

  site_config {
    application_stack {
      php_version = "8.3"
    }
  }
}

Bicep equivalent:

resource site 'Microsoft.Web/sites@2023-01-01' = {
  name: 'my-php-app'
  location: location
  properties: {
    serverFarmId: plan.id
    siteConfig: {
      linuxFxVersion: 'PHP|8.3'
    }
  }
}

Enforce with Azure Policy

Use a policy to deny or audit App Services that run a non-approved runtime. A custom policy can match on Microsoft.Web/sites/config and check the linuxFxVersion against an allowed list, flagging anything that drifts to an older PHP branch.

Gate it in CI/CD

Add a check to your pipeline that fails the build if the configured runtime is not in your approved set. A simple shell step works:

CURRENT=$(az webapp config show -g my-rg -n my-php-app --query "linuxFxVersion" -o tsv)
ALLOWED="PHP|8.3 PHP|8.4"

if [[ ! " $ALLOWED " =~ " $CURRENT " ]]; then
  echo "Disallowed PHP runtime: $CURRENT"
  exit 1
fi

Tip: Lensix runs appservice_oldphp continuously across your subscriptions, so you get alerted the moment a runtime falls out of support rather than discovering it during an audit or an outage. Wire the finding into your ticketing system to make the upgrade part of routine maintenance.


Best practices

  • Track the PHP support calendar. Each PHP branch gets two years of active support plus one year of security fixes. Plan upgrades around those dates rather than reacting to them.
  • Stay on N or N-1. Run the latest supported branch or one behind it. This keeps you off the EOL edge and avoids the painful multi-version jumps.
  • Use slots for every runtime change. Treat a PHP bump like any other deploy: stage, validate, swap, and keep the old slot warm for rollback.
  • Test against the target version in CI. Run your test suite under the new PHP version before you touch infrastructure, so compatibility issues surface in the pipeline rather than in production.
  • Inventory all PHP workloads. Old versions hide on forgotten apps. A continuous scan across subscriptions catches the App Service nobody remembers deploying.
  • Migrate Windows PHP apps to Linux. Built-in PHP on Windows App Service is deprecated. Move those workloads to Linux App Service to stay on a supported path.

Keeping a PHP runtime current is unglamorous work, but it is one of the cheapest security wins you can make on Azure. The upgrade path is short when you do it on schedule and expensive when you let it slide. Pin the version, enforce it in policy, and let an automated check tell you the day it goes stale.