PHP2Shell and Docker: Rebuilding PHP Images the Right Way

By: Irina Shvaya | October 23, 2026
This guide is part of our PHP2Shell Resource Center: fixed versions, how to check your PHP version, WordPress, Drupal and Joomla steps, mitigations and signs of a hack.

As of 23 October 2026, the official Docker php image has fixed tags for every branch it still maintains: 8.5.12, 8.4.27, 8.3.36 and 8.2.35, published on 21 October. The 8.6 release candidate tag moved to RC4, which contains the fixes, on 23 October. The tags for PHP 8.1 and older have not been rebuilt, so no fixed official image exists for them.

The direct answer: a container carries its own copy of PHP. Updating the host server doesn't touch it, and running apt upgrade inside the container doesn't either. You fix PHP2Shell (CVE-2026-109618 and CVE-2026-109619) in Docker by rebuilding or pulling an image built on a fixed PHP, then replacing every running container that uses it.

This guide covers the official image, images you build yourself, application images such as wordpress and drupal, and how to prove the new PHP is what's running.

Key Takeaways

  • Use php:8.5.12, 8.4.27, 8.3.36 or 8.2.35, or a newer tag on those branches. Moving tags such as php:8.4-fpm now point to fixed builds.
  • The official image compiles PHP from php.net's source, so php -v inside it shows the true version. That is not true of images that install a distribution's PHP packages.
  • Rebuild with --pull so you get the fixed base image, then recreate the containers. A pull alone changes nothing that is already running.
  • If you pulled php images during a release-day tag glitch on the afternoon of 21 October (UTC), pull again and check the digest.
  • There is no fixed official image for PHP 8.1 or older. Move to 8.2 or newer.

Why apt upgrade Inside a Container Does Nothing for PHP

The official php image does not install PHP from Debian or Alpine packages. Its Dockerfile downloads the release from php.net, checks its SHA256 checksum and compiles it. One of the image maintainers put it simply on 21 October: "Our PHP isn't installed via APT and our images aren't based on Ubuntu."

The image even blocks Debian's PHP packages on purpose. Its Docker Hub page explains that "installing Debian's PHP packages in this image leads to two conflicting installations of PHP in a single image."

Two things follow:

  • apt-get upgrade inside the container won't fix PHP. PHP isn't an apt package there. The fix arrives only as a new image.
  • Changes inside a running container don't last. Even if you could patch it in place, the next restart from the old image would bring the old PHP back.

Updating the host isn't enough either. Microsoft's guidance for its own platform says to "Rebuild and redeploy container images that include their own PHP runtime, since updating the host does not update PHP inside an image." Google gives the same advice for Kubernetes: "Update your container images with a patched version of PHP and redeploy your pods."

Fixed Official Tags

The official images rebuilt on 21 October build PHP from the fixed releases. The variants are Debian trixie and bookworm (cli, apache, fpm and zts) and Alpine 3.24 and 3.23.

BranchFixed tagStatus as of 23 October 2026
8.58.5.12Fixed; also the latest tag
8.48.4.27Fixed
8.38.3.36Fixed
8.28.2.35Fixed; PHP 8.2 reaches end of life on 31 December 2026
8.6 (test)8.6-rc (8.6.0RC4)Fixed release candidate, updated 23 October; not for production
8.1NoneLast pushed 2 January 2026; not rebuilt
8.0, 7.4, 5.6NoneLast pushed November 2023, November 2022 and January 2019

A tag like php:8.4-fpm moves to each new release on that branch, so a fresh pull of it today gets 8.4.27 or later. A tag like php:8.4.27-fpm stays on that exact release. The PHP2Shell version lookup confirms whether a given version is fixed.

If you are stuck on an 8.1 or older image, nothing official will fix it. PHP published only source-code backports for 7.4, 8.0 and 8.1. Plan the move to a supported branch. US, UK and EU cybersecurity agencies advise taking systems offline or isolating them if you can't patch.

The Release-Day Tag Glitch

The official images were updated quickly, but not smoothly. Shortly after the update was merged at about 15:16 UTC on 21 October, users reported that "Many PHP images do not have a linux/amd64 variant so many fail to even pull" and that php:8.5-fpm-alpine and php:8.5.12-fpm-alpine "are currently not pointing at the same image." A maintainer replied, "Sorry, had a deploy glitch - updated tags are pushing now," and both reports were closed at about 16:40 UTC (issue #22546).

If you pulled php images on the afternoon of 21 October, pull them again now. The Docker documentation notes that "Docker prints the digest of the image after the pull has finished." Compare that digest with the one your running containers use. If they differ, your containers are on an older image.

How to Rebuild and Redeploy

The pattern is always the same: get the fixed image, then replace the running containers.

If you use a published image as is

With Docker Compose:

docker compose pull
docker compose up -d

Docker's documentation says compose pull "does not start containers based on those images," so the second command matters. It recreates containers whose image changed.

If you build your own image FROM php

Rebuild from the fixed base. The Docker build reference documents --pull ("Always attempt to pull all referenced images") and --no-cache ("Do not use cache when building the image"). An example for a single image (replace the name with yours):

docker build --pull --no-cache -t myapp:php8.4.27 .

Or with Compose:

docker compose build --pull
docker compose up -d

Without --pull, Docker may reuse an old base image already on disk.

If your image installs a distribution's PHP

Some teams build FROM debian or ubuntu and install PHP with apt, or use another vendor's base image. Then the distribution's fixed packages apply, and they often keep old version numbers. Ubuntu 24.04's fixed php8.3, for example, is 8.3.6-0ubuntu0.24.04.13. Rebuild with --pull --no-cache so the package install step actually runs again instead of being served from cache. FrankenPHP's documentation gives the same caution about cached layers.

Kubernetes and other orchestrators

Push the rebuilt image under a new tag or by digest, update the deployment to use it and roll it out. A plain restart can come back on the cached old image. Our guide to restarting PHP workers covers Compose and Kubernetes in more detail, including the image pull policy trap.

Pin What You Deploy

Moving tags make patching easy, but they also make it hard to know what you are running. Two habits help:

  • Use version tags you can read. FROM php:8.4.27-fpm tells everyone which PHP is inside. FROM php:8.4-fpm doesn't.
  • Pin production by digest. Docker's documentation explains that pulling by digest lets you "pin" an image to that version, so a deploy can't silently change underneath you. Update the digest on purpose when a security release lands.

Base images are part of your software supply chain, like plugins and packages. Our guide to supply chain security for plugins, apps and packages covers keeping an inventory of what you pull in.

Application Images: wordpress, drupal, joomla and Others

Official application images are built on the php image. As of 23 October 2026, all three popular CMS images were rebuilt on 22 October:

  • wordpress:latest is WordPress 7.1.3 on php8.3 with Apache.
  • drupal:latest is Drupal 11.4.11 on php8.5 with Apache.
  • joomla:latest is Joomla 6.1.4 on php8.4 with Apache.

Pull the new image and recreate the container. Many other application images were rebuilt too, but not all. For any third-party image, check the PHP inside it yourself (next section). An image tag usually tells you the app version, not the PHP version.

The -apache variants run PHP as mod_php under Apache's prefork model. PHP calls mod_php the highest-risk setup for these flaws, so patch those first. Our Apache mod_php guide explains why. FrankenPHP has its own images with PHP built in; see our FrankenPHP and PHP2Shell guide.

How to Verify the PHP Inside a Container

Check the running container, not just the image on disk. Examples (replace the service, container or image name with yours):

docker compose exec app php -v
docker exec mycontainer php -v
docker run --rm php:8.4-fpm php -v

Every official php variant includes the command-line PHP at /usr/local/bin/php, and because the image compiles upstream PHP, the version it prints is accurate: 8.4.27 or later means fixed. On images that use a distribution's PHP, compare the package version with the distribution's advisory instead. Our guide on how to check your PHP version covers both cases.

For official 8.2 to 8.5 builds there is one more check. PHP's manual says the new memory_hard_limit_percent setting is "Available as of PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35," and that if it "is not recognized, the PHP version in use is affected." For example, docker compose exec app php -i | grep memory_hard_limit_percent should print a line. Don't use this test on backported distribution builds, which may not have the setting.

Finally, confirm that the container itself is new. docker compose ps shows how long each one has been up. A container that has been running for days was not replaced.

Settings and Mitigations in Containers

The official image ships php.ini-development and php.ini-production and says "It is *strongly* recommended to use the production config" in production. Custom settings go in files copied into the $PHP_INI_DIR/conf.d/ directory. That is a php.ini-level location PHP reads at startup, which is what PHP's interim settings require.

One setting is worth keeping even on fixed images. A separate, lower-risk issue, CVE-2026-115560, affects patched releases too, and PHP suggests setting session.upload_progress.enabled=0 until its next regular release if you don't use that feature. In a Dockerfile, for example, copy a small ini file with that line into $PHP_INI_DIR/conf.d/ and rebuild. Setting it with ini_set() in code, or in .user.ini, does not work for this. The full list is in our PHP2Shell interim mitigations guide.

One hardening reminder from the image's own documentation: the -fpm variant's FastCGI port is "*extremely* insecure to expose outside of a private container network," so don't publish it with -p. If your containers serve a headless or decoupled site, our headless and custom website security guide covers the wider picture.

Conclusion

As of 23 October 2026, Docker's official php image is fixed on 8.2.35, 8.3.36, 8.4.27 and 8.5.12, and the 8.6 release candidate on RC4. Nothing changes until you rebuild with a fresh base, recreate every container, and check php -v inside the running ones. If you pulled during the 21 October glitch, pull again. Images on PHP 8.1 or older have no official fix, so plan the upgrade now. If you run many services and want help rebuilding and verifying them, our emergency PHP patching team can work through them with you. Every PHP2Shell guide is in our PHP2Shell Resource Center.

Frequently Asked Questions

I updated my server. Are my containers fixed?

No. Each container has its own PHP from its image. Rebuild or pull a fixed image and recreate the containers.

Can I run apt-get upgrade inside the official php container?

It won't update PHP. The official image compiles PHP from php.net's source and blocks Debian's PHP packages, so the fix comes only from a new image.

Which official tags are fixed?

php:8.5.12, 8.4.27, 8.3.36 and 8.2.35, and the moving tags on those branches (such as 8.4-fpm) as of 21 October 2026. The 8.6-rc tag is on the fixed RC4. Tags for 8.1 and older have not been rebuilt.

Do I need to rebuild the wordpress image?

Pull the current wordpress image and recreate your container. As of 23 October 2026, wordpress:latest was rebuilt on 22 October on php8.3. If you build on top of it, rebuild with --pull.

What was the 21 October tag glitch?

For a short time after the release, some php tags lacked an amd64 image or pointed at mismatched images. The maintainers fixed it at about 16:40 UTC. If you pulled that afternoon, pull again and compare digests.

Put this into action with eSEOspace

We help businesses grow with maintenance & support that actually performs. Explore the services behind this guide:

Book a free strategy call →

Get a FREE Audit

We'll perform a comprehensive SEO, AEO, GEO & CRO audit of your website — completely free — and show you exactly how to outrank your competitors.

Don't have a site yet? Get in touch →

Get a FREE GEO/AEO/SEO Audit

We'll analyze your site's SEO, GEO, AEO & CRO — completely free — and show you exactly how to get found across Google and AI answers.

Don't have a site yet? Get in touch →

You Might Also like to Read