What happened
FrankenPHP is a modern PHP application server built on the Caddy web server. It is often deployed as the ready-made Docker image dunglas/frankenphp, for example for Symfony or Laravel applications. On February 5, 2026, the project maintainers published security advisory GHSA-x9p2-77v6-6vhf on GitHub and rated it critical.
The problem is not in FrankenPHP’s own code but in how its Docker images were built. Images were only rebuilt when a new base image tag appeared. Alpine Linux, PHP and Go, however, usually ship security fixes under an existing tag, so FrankenPHP images stayed on older, vulnerable libraries. As an example, the maintainers cite CVE-2025-15467 in the libcrypto3 library, which allows remote code execution.
VulnCheck registered the issue as CVE-2026-128027 on November 12, 2026, and the US National Vulnerability Database (NVD) published it on November 13, 2026. The EU vulnerability database EUVD lists it as EUVD-2026-125075. It is not in the CISA KEV catalog, EUVD records no exploitation, and the maintainers do not mention any attacks. The issue was reported and fixed by Tim Nelles.
Why it is dangerous
This is a dependency on a vulnerable third-party component, which VulnCheck classifies as CWE-1395. Picture a building firm that fits locks from a supplier into every house. The supplier quietly replaces a faulty lock with a fixed one but keeps the same catalog number. The firm only watches the number, so it keeps fitting old locks from the warehouse. That is exactly how fixes from Alpine, PHP and Go never made it into FrankenPHP images.
According to VulnCheck, remote attackers could exploit known flaws in the stale system libraries to run their own code on the server. The maintainers are more cautious: they say users may have been running environments with known vulnerabilities, even when using the latest build of their tag. In practice, whether a given library flaw can be exploited also depends on how the application uses that library.
If an attack succeeded, the attacker would control the application container. They could read the database, passwords and API keys stored in environment variables, tamper with the website, or try to reach other systems on the network. Whether they could also break out to the host server depends on how the container is configured.
The CVSS score rates severity on a scale from 0 to 10. VulnCheck, which assigned the CVE, gives it 9.8 under CVSS 3.1, matching the FrankenPHP advisory: the attack works over the network, is simple, and needs no login or user interaction. Under the newer CVSS 4.0, VulnCheck rates it 9.3. The EPSS score, which estimates the probability of exploitation in the next 30 days, is 0.86%, higher than roughly 59% of scored vulnerabilities. The CISA KEV catalog, a list of vulnerabilities known to be exploited, does not include it.
Who is affected
Affected are the official dunglas/frankenphp Docker images before version 1.1.11 and any custom images built on them, meaning those with a FROM dunglas/frankenphp line in their Dockerfile. The maintainers point out that even users running the latest build of a specific tag may have been exposed.
Typical environments include:
- business web applications and online shops running PHP in Docker or Kubernetes
- Symfony or Laravel applications deployed in FrankenPHP containers
- development and staging servers reachable from the internet
- CI/CD pipelines that build custom images from the FrankenPHP image
Classic PHP setups with Apache or PHP-FPM that do not use FrankenPHP are not affected. The maintainers’ advisory covers the Docker images and does not mention other ways of installing FrankenPHP.
How to check if you are affected
The commands below only read information and change nothing. First, find out which containers run from a FrankenPHP image:
docker ps --format '{{.Names}} {{.Image}}' | grep -i frankenphp
Custom images have their own names, so that command will miss them. This one prints the FrankenPHP version in every running container:
docker ps --format '{{.Names}}' | while read c; do v=$(docker exec "$c" frankenphp version 2>/dev/null) && echo "$c: $v"; done
Any version below 1.1.11 means you are affected. For Alpine-based images, also check the OS release and the libcrypto3 library. Replace container-name with the container’s name. The maintainers say fixes arrived in Alpine 3.20.9, 3.21.6, 3.22.3 and 3.23.3. An older release in the same branch is a warning sign.
docker exec container-name cat /etc/alpine-release
docker exec container-name apk list --installed libcrypto3
An image built before February 4, 2026, when the maintainers changed their build process, may contain stale libraries. The first command shows the build date of every image on the server. Run the second in your projects directory to find FrankenPHP references in Dockerfile and Compose files.
docker image ls --format '{{.Repository}}:{{.Tag}} {{.CreatedAt}}'
grep -rni frankenphp --include='Dockerfile*' --include='*compose*.yml' --include='*compose*.yaml' .
How to fix it
The fixed version is 1.1.11. Since February 4, 2026, the maintainers compare base images against upstream registries every day and automatically rebuild FrankenPHP images whenever anything changes. The fix will not reach you on its own, though. You need to pull the image again and recreate your containers.
Follow these steps:
- List every server, project and CI pipeline that uses FrankenPHP.
- If you use a tag older than 1.1.11, switch to 1.1.11 or later.
- Pull the current build of your tag, for example
docker pull dunglas/frankenphp:latest. - If you build your own image, rebuild it with the
--pullflag so Docker fetches fresh base layers. - Recreate your containers. Pulling an image alone does not change a running container.
- Use the commands from the check section to confirm the new version is running.
docker pull dunglas/frankenphp:latest
docker build --pull -t my-app .
With Docker Compose, run this in the project directory:
docker compose pull --ignore-buildable
docker compose build --pull
docker compose up -d
The only workaround the maintainers list is forcing fresh base layers with --pull. They mention no other interim measures. Start with internet-facing systems, then internal ones, and finish with development environments.
Going forward, rebuild your own images on a schedule, for example weekly, and scan them with a vulnerability scanner such as Trivy or Grype. That way you will catch similar problems in other images too.
What if you may already be compromised
Neither the maintainers nor VulnCheck have published specific indicators of compromise. If a vulnerable container was reachable from the internet for a long time, do a basic review before you remove it, while the traces are still there. The following commands only read data:
docker logs container-nameshows the logs. Look for unusual errors, process crashes and unfamiliar requests.docker diff container-namelists files added or changed compared to the image. New PHP files in the web root and executables in/tmpare suspicious.docker top container-namelists running processes. You should see nothing besides FrankenPHP and your application.- In the application and database, look for unknown admin accounts and recent permission changes.
- On the firewall, check for unexpected outbound connections from the server.
If you find anything suspicious, replacing the container is not enough. Rotate database passwords, API keys and any other secrets the container could access. Bring in an incident response specialist, especially if the container had the Docker socket or host directories mounted, or ran with elevated privileges. In that case the attacker may have reached the host server itself.