Cover image for LiveWyer blog post: The PHP2Shell flaw your Trivy scans cannot see
Engineering • 9min read

The PHP2Shell flaw your Trivy scans cannot see

Trivy reports no PHP2Shell findings in vulnerable official PHP images. We tested it, and explain why.

Written by:

Avatar Louise Champ Louise Champ

Published on:

Last updated on:

If you rely on Trivy to scan your container images, and your PHP images are built on the official php image, it will tell you they are clear of PHP2Shell, whether they are or not. PHP2Shell is being exploited right now, CISA lists both of its CVEs as known exploited vulnerabilities, and an attacker who lands it runs their own code on your PHP workers.

On 29th October 2026, we pulled the official php:8.4.26-fpm image from Docker Hub, which carries both PHP2Shell vulnerabilities (CVE-2026-109618 and CVE-2026-109619), and scanned it with the latest releases of Trivy and Grype. This is what Trivy had to say:

$ trivy image --scanners vuln php:8.4.26-fpm
Report Summary
php:8.4.26-fpm (debian 13.7)
Total: 1878 (UNKNOWN: 83, LOW: 921, MEDIUM: 754, HIGH: 116, CRITICAL: 4)

That is 1,878 findings, four of them Critical, and PHP2Shell is not one of them. Grype, on the other hand, flagged both CVEs against the PHP binaries (output trimmed to the PHP2Shell rows):

$ grype php:8.4.26-fpm
NAME     INSTALLED  FIXED IN                         TYPE    VULNERABILITY    SEVERITY
php-cli  8.4.26     8.2.35, 8.3.36, *8.4.27, 8.5.12  binary  CVE-2026-109618  Critical
php-fpm  8.4.26     8.2.35, 8.3.36, *8.4.27, 8.5.12  binary  CVE-2026-109618  Critical
php-cli  8.4.26     8.2.35, 8.3.36, *8.4.27, 8.5.12  binary  CVE-2026-109619  High
php-fpm  8.4.26     8.2.35, 8.3.36, *8.4.27, 8.5.12  binary  CVE-2026-109619  High

The fixed image, php:8.4.27-fpm, came back free of PHP2Shell on both scanners, so Grype is not simply flagging every PHP image it sees.

What is PHP2Shell, and does it reach containers?

PHP2Shell is a pair of use-after-free bugs in the PHP engine itself, which let an unauthenticated attacker run code as the PHP worker, and they reach a container in exactly the same way they reach a server.

CISA’s alert lists every common way of serving PHP as affected: Apache with mod_php, PHP-FPM, php-cgi, FrankenPHP, and LiteSpeed.

The PHP project released fixes in 8.5.12, 8.4.27, 8.3.36, and 8.2.35 on 21st October 2026. Exploitation attempts had already been seen on 17th October. PHP 8.1 and older are out of support, so they get no fix at all.

In a container, the fix means rebuilding every image on a patched PHP and rolling it out, since patching the nodes does nothing for the PHP inside an image.

It is the same drill a lot of platform teams went through for the ingress-nginx CVEs in 2025, and the image scanner is usually what tells you which images still need it.

Test 1: Trivy passes a vulnerable PHP image

We scanned two official PHP-FPM images from Docker Hub, one either side of the fix, with both scanners. Each scanner pulled a vulnerability database updated on the day of the test.

Scannerphp:8.4.26-fpm (vulnerable)php:8.4.27-fpm (fixed)
Trivy 0.76.1 (latest)No PHP2Shell findingsNo PHP2Shell findings
Grype 0.121.0 (latest)CVE-2026-109618 (Critical) and CVE-2026-109619 (High)No PHP2Shell findings

We ran php -v inside each image to confirm the tags held the versions they claimed. Trivy gave 1,878 findings in the vulnerable image, 1,877 in the fixed one, and no mention of PHP in either.

The Alpine variants, php:8.4.26-fpm-alpine and php:8.4.27-fpm-alpine, gave the same split: Trivy found no PHP2Shell in either, and Grype flagged the vulnerable one.

Test 2: WordPress shows the same blind spot

WordPress runs 40% of all websites, and the official WordPress images use Apache with mod_php. The PHP project rates this setup as most at risk. We compared wordpress:php8.1-apache with wordpress:latest, which was rebuilt on PHP 8.3.36 on 28th October.

The php8.1-apache tag runs PHP 8.1.34 and was last updated on 1st January 2026. It is still listed on Docker Hub, it still pulls, and it will never receive a fix, because there is no PHP 8.1 fix for anyone to build.

Scannerwordpress:php8.1-apache (vulnerable)wordpress:latest (fixed)
Trivy 0.76.1No PHP2Shell findings (9,584 findings in total)No PHP2Shell findings
Grype 0.121.0Both CVEs, on libphp (the Apache module) and php-cliNo PHP2Shell findings

Let’s say your team runs that image. The Trivy report will hand you 9,584 findings to triage, but the one being exploited is not on the list.

Test 3: the cluster’s own reports miss it too

Some teams also scan what is running in the cluster, rather than what passes through CI. We installed the latest Trivy Operator (0.36.1, which runs Trivy 0.76.1) into a throwaway kind cluster with its default values, and deployed one Deployment on php:8.4.26-fpm and another on php:8.4.27-fpm.

The two VulnerabilityReport resources came back with 1,878 and 1,877 findings, and neither one listed PHP2Shell or any PHP package at all. So a cluster can be running the vulnerable image, while its own security reports report nothing about it.

Why does Trivy miss it?

Trivy can only find software if there is a record of it in the container image, such as the package manager’s database or a bundled SBOM. There is nothing in the official PHP images which records PHP itself.

Their Dockerfiles compile PHP from source into /usr/local, so no Debian package owns /usr/local/bin/php or /usr/local/sbin/php-fpm. Running dpkg -S against either of these directories returns nothing. Trivy’s inventory of php:8.4.26-fpm came to 172 Debian packages, none of them PHP.

To be fair to Trivy, this is how it is designed to work, and runtimes installed outside the package manager have been a known open issue for a long time.

Grype is able to catch PHP2Shell because it can also read the version strings out of the binaries themselves, including the Apache module.

You may be relying on Trivy without knowing it

Plenty of teams are running Trivy without having chosen it. After all, it is the scanner baked into:

When can you rely on Trivy?

Trivy is a good scanner for anything a package manager or a lockfile records, which covers most of what sits in a typical image. It reads the distro’s own security advisories for packages installed with apt, apk, or dnf, so it understands backported fixes. It also reads your application’s lockfiles, such as composer.lock and package-lock.json, and the module versions Go embeds in its binaries.

It will also read an SBOM that ships inside the image. For example, Bitnami’s images carry one for every component, so Trivy does flag PHP2Shell as Critical in Bitnami’s frozen bitnamilegacy/phpmyadmin image (which runs PHP 8.2.29, and will never get the fix).

Where it falls short is anything that is compiled, unpacked, or copied into an image with no package or SBOM to describe it. That includes the official PHP images, any runtime installed with curl | tar or make install, and a static binary in a scratch image. The same open issue names Java and Node.js runtimes as examples alongside PHP.

The quickest way to check an image is to look at the SBOM Trivy generates for it. If the runtime your application runs on is missing from the output of trivy image --format cyclonedx, it is not being scanned by Trivy. Check its version inside the running container instead, or add a scanner that reads binaries, as Grype did in our tests.

What should you check today?

Start with what is running in your clusters, and then treat the scan report as a second opinion.

  • Find out whether your scanning runs on Trivy. If any of it does, treat every clean PHP2Shell result it gives you as unknown until you have checked the PHP version yourself.
  • Check the PHP version inside each running container. php -v is reliable for the official images. For distro packages, check the package version, since distros backport fixes without changing the version php -v reports.
  • Look for tags frozen on PHP 8.1 or older. No rebuild is coming for those, so the fix is an upgrade to 8.2 or later. 8.2 itself leaves security support on 31st December 2026.
  • Replace pods running on a floating tag. A tag such as latest or 8.4-fpm now points at a fixed image, but a running pod keeps the image it started with, and for a version tag the default IfNotPresent pull policy means a restart can reuse the old image from the node’s cache.
  • Check what a rollback would bring back. A pinned digest, an old Helm revision, or a GitOps sync to an earlier commit can put the vulnerable image straight back into the cluster.
  • Keep the evidence before you replace a pod you suspect. Exploitation did start before the fix shipped. A rollout replaces the container and its filesystem, but it also throws away what you would need to tell whether that pod was hit.

Patching also says nothing about how far an attacker could get before the fix. On a cluster with default settings, a compromised PHP pod can reach every other pod and the internet, and it has a service account token mounted, because nothing restricts it until someone adds network policies and pod security settings.

We’ve made the case for namespaces with network policy doing the isolating before, and PHP2Shell is a good test of whether that isolation is in place.

How can LiveWyer help?

LiveWyer is a cloud native consultancy that builds and runs Kubernetes platforms. We were one of London’s first Kubernetes consultancies, and since 2015 our engineers have designed and operated platforms on AWS, Google Cloud Platform, Azure, and on premises.

If PHP2Shell has left you unsure what is running in your clusters, talk to our engineers. We can help you find every PHP runtime across your images, check what your scanners can and cannot see, and work out what a compromised pod could reach. If the answer points to a wider change in how you build and ship images, our Cloud Platform Engineering pilot builds it around one of your own applications in three weeks.

If you would like our next teardown when it lands, The Wyer, our monthly newsletter, has a sign-up form at the foot of this page.

Frequently asked questions

Which PHP versions fix PHP2Shell?

PHP 8.5.12, 8.4.27, 8.3.36, and 8.2.35, released on 21st October 2026, fix both CVE-2026-109618 and CVE-2026-109619. PHP 8.1 and older are out of support and have no official fix. Some Linux distributions backport fixes into their own 8.1 packages, but the official Docker images do not get them.

Is FrankenPHP affected by PHP2Shell?

Yes. CISA’s alert lists FrankenPHP alongside PHP-FPM, mod_php, php-cgi, and LiteSpeed, because the bugs are in the PHP engine which all of them embed. Fixing it means moving to a FrankenPHP build on one of the fixed PHP versions.

Thank you for reading

If you enjoy our writing and would like to see more, add us as a Preferred Source on Google and you'll be more likely to see us in your results.

LiveWyer is a London-based consultancy specialising in deploying small, agile engineering teams to design and implement modern Cloud and Platform solutions.

Talk to a specialist