FrankenPHP and PHP2Shell: Worker Mode, Updates and Restarts
FrankenPHP and PHP2Shell: Worker Mode, Updates and Restarts

As of 23 October 2026, FrankenPHP 1.13.2 and later include the PHP versions that fix PHP2Shell. FrankenPHP 1.13.2, released on 21 October 2026, builds its Docker images with PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12, and its static binaries with PHP 8.5.12. Version 1.13.3 followed on 23 October as a bug fix release.
FrankenPHP is an application server for PHP built on the Caddy web server, with PHP compiled in. That changes how you patch. You don't update PHP on its own; you install a fixed FrankenPHP binary or image, then restart the process or replace the container. Restarting workers through FrankenPHP's admin API does not do it.
This guide covers what PHP's advisories say about FrankenPHP, how to update each install method, why worker mode needs a full restart, and how to confirm you are on a fixed build.
Key Takeaways
- PHP lists FrankenPHP among the setups at risk and calls it "likely susceptible to application-independent attacks" for CVE-2026-109618.
- Use FrankenPHP 1.13.2 or later. Docker images carry PHP 8.2.35, 8.3.36, 8.4.27 or 8.5.12; static binaries carry 8.5.12.
- Updating means a new binary or image plus a restart of the process or container. A worker restart or config reload alone keeps the old PHP.
- 1.13.2 also fixes four flaws in FrankenPHP itself, including a separate worker-mode data leak (GHSA-4gfw-9v29-gp9h).
- Pin image tags to a FrankenPHP and PHP version you can check, and rebuild custom images from a fixed base.
What PHP's Advisories Say About FrankenPHP
PHP's 21 October 2026 announcement lists "all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed." The two GitHub advisories add detail at summary level:
- CVE-2026-109618 (GHSA-w8hw-w9fx-j79w): "Source analysis indicates that FrankenPHP, analogous to Apache mod_php, calls the request shutdown procedure unconditionally, making it likely susceptible to application-independent attacks."
- CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp): "An equivalent early configuration consumer was not established in the default configuration of FrankenPHP. This does not make this environment immune."
"Application-independent" means the risk does not depend on which PHP app you run. In plain terms, treat every FrankenPHP deployment as exposed until it runs a fixed build. Our CVE-2026-109618 summary explains that flaw at advisory level.
Fixed FrankenPHP Releases
From the FrankenPHP releases page:
| Release | Date | What it contains |
|---|---|---|
| 1.13.2 | 21 October 2026 | Security release. Docker images built with PHP 8.2.35, 8.3.36, 8.4.27 and 8.5.12; static binaries with PHP 8.5.12. Four FrankenPHP fixes. |
| 1.13.3 | 23 October 2026 | Bug fix release (worker lookup with symlinked document roots, crashes from some extensions' signal handlers, crashes of musl static binaries on some CPUs). No further PHP2Shell change listed. |
The release notes say the PHP2Shell flaws "have no complete mitigation besides upgrading" and that "Upgrading is strongly recommended." Treat any FrankenPHP version before 1.13.2 as unpatched unless you can confirm the PHP version inside it.
Two upgrade notes in 1.13.2 can catch people out:
- macOS: "Binaries are only published for Apple Silicon." There is no Intel Mac binary any more; Intel users build from source.
- Linux glibc builds: "The -gnu binary now requires glibc 2.28 or later, instead of 2.17." Very old Linux servers may need the statically linked binary instead.
How You Installed FrankenPHP Decides How You Update
FrankenPHP's documentation lists several install methods, and PHP lives in a different place in each:
| Install method | Where PHP comes from | How to get the fix |
|---|---|---|
| Docker images (dunglas/frankenphp) | Built into the image | Pull or rebuild from a 1.13.2+ tag, then replace containers |
| Standalone binary (Linux, macOS) | Compiled into the binary (PHP 8.5) | Replace the binary with 1.13.2+, then restart |
| Windows archive | "Windows archives contain the official PHP binary for Windows" | Install a 1.13.2+ archive, check the PHP version it reports, then restart the service |
| deb, rpm or apk packages | Separate php-zts packages from FrankenPHP's package maintainers | Run your normal system update, then restart the frankenphp service |
| Homebrew | The Homebrew package | Upgrade the package, then restart the brew service |
For the deb and rpm packages, check that the installed php-zts packages are at a fixed PHP version (8.2.35, 8.3.36, 8.4.27 or 8.5.12). FrankenPHP's documentation does not list those package versions, so confirm with the package manager or with phpinfo after the restart.
Updating Docker Images
Most production FrankenPHP sites run in containers. FrankenPHP's Docker documentation says image tags follow the pattern dunglas/frankenphp:<frankenphp-version>-php<php-version>-<os>, with trixie, bookworm or alpine as the OS, and with versions that can be as specific as a patch release.
- Pin a fixed version. For example, FROM dunglas/frankenphp:1.13.3-php8.4.27-trixie (use your own PHP branch and OS). A pinned tag makes it obvious which FrankenPHP and PHP you run. Docker Hub showed this tag updated on 23 October 2026.
- Rebuild custom images. If your Dockerfile starts from a FrankenPHP image, rebuild it. Docker documents docker compose build --pull to "Always attempt to pull a newer version of the image." FrankenPHP's production guide warns that "Docker can have a cache layer" and suggests rebuilding "with the --no-cache option to avoid cache issues."
- Replace the running containers. docker compose up -d recreates containers whose image changed. Pulling or building alone leaves the old container running.
- Check custom builder images. If you compile your own FrankenPHP with extra Caddy modules, rebuild from a 1.13.2+ builder image. The docs note the builder image "contains a compiled version of libphp."
FrankenPHP's docs say its images are rebuilt "when a new release is tagged" and "daily at 4 am UTC, if new versions of the official PHP images are available." That helps if you use a floating tag, but you still have to pull and recreate. Container steps for every platform are in our guide to restarting PHP workers.
Updating the Static Binary or a Packaged Install
If you run the standalone binary, download FrankenPHP 1.13.2 or later from the releases page and replace the old file. Then restart whatever runs it: your systemd unit, supervisor or Windows service.
Replacing the file does not change the process that is already running. Caddy's documentation says the same of its own upgrade command: it "only replaces the binary on disk." The old process keeps serving the old PHP until it is restarted.
For the deb and rpm packages, FrankenPHP's docs name the systemd service frankenphp, so after the system update run:
sudo systemctl restart frankenphp
On Windows, FrankenPHP's production guide notes that "Windows services cannot be reloaded" and offers frankenphp.exe reload for configuration changes. A configuration reload is not a PHP update. Stop and start the service after installing the new archive.
Worker Mode: Why a Worker Restart Is Not Enough
In worker mode, FrankenPHP boots your application once and keeps it in memory between requests. The worker documentation describes several ways to restart workers:
- A graceful restart of all workers through the Caddy admin API, if the admin endpoint is enabled: curl -X POST http://localhost:2019/frankenphp/workers/restart
- The --watch option, which restarts workers when files change.
- A MAX_REQUESTS setting in the worker script, which restarts a worker after a set number of requests.
As FrankenPHP's docs describe them, all three restart your worker scripts inside the FrankenPHP process that is already running. Because PHP is compiled into that process, they keep the same PHP. They are useful for deploying new application code. They do not apply a PHP security fix. For PHP2Shell, install the fixed binary or image and restart the whole process or container.
A related note: the worker docs warn that some state persists between requests on the same worker thread, including static variables and $_ENV, which "is currently not reset between requests." That is an application design issue, separate from PHP2Shell, but it is a good reason to review worker scripts while you are in there.
FrankenPHP's Own Fixes in 1.13.2
Separately from PHP2Shell, 1.13.2 fixes four vulnerabilities in FrankenPHP itself. They are another reason to upgrade:
- GHSA-6q3j-62j9-f9hh (high): embedded apps were extracted to a predictable shared temp directory, which a local user could abuse.
- GHSA-fq24-r53r-xcx3: requests from clients that had disconnected could keep the PHP thread pool busy.
- GHSA-ccgp-ch9h-533f: self-referencing arrays could crash the whole process.
- GHSA-4gfw-9v29-gp9h: in worker mode, error_get_last() and libxml_get_errors() results "could leak fragments of a previous client's input and server paths into the next request served by the same thread." These are now cleared after each request.
The last one sounds similar to PHP2Shell's second flaw because both involve leftover data between requests. It is a different issue, in FrankenPHP rather than in PHP, with its own advisory.
How to Confirm You Are on a Fixed Build
- Check the version you deployed. For Docker, look at the image tag in your Dockerfile or compose file. A tag such as 1.13.3-php8.4.27 states both versions. For binaries, check the release you downloaded.
- Check the process restarted. docker compose ps shows how long each container has been up. For the packaged service, systemctl status frankenphp shows when it started. Either should be after your update.
- Check the PHP version the site serves. A temporary phpinfo() page shows the PHP version FrankenPHP is actually running. Delete it right after. Our guide on checking your PHP version explains how.
The version should read 8.2.35, 8.3.36, 8.4.27 or 8.5.12 or later on its branch. The full list is in our fixed versions table.
If You Can't Upgrade Today
Upgrading is the only complete fix. If a rebuild has to wait, PHP's interim settings, such as session.upload_progress.enabled=0, reduce exposure to specific paths. Set them in php.ini. FrankenPHP's production example enables PHP's production settings by moving php.ini-production into place in $PHP_INI_DIR, so that is the file to edit in an image. Then restart the process. Every setting and its side effects are in our interim mitigations guide.
Keep upload progress off after you upgrade too, if you don't use it. PHP suggests this until its next regular release because of a separate, unusual-setup issue, CVE-2026-115560, that affects fully patched releases.
Conclusion
FrankenPHP makes PHP2Shell simple to fix in one sense: the fixed PHP comes with the FrankenPHP release. Move to 1.13.2 or later, rebuild any custom images, and restart the process or replace the container. Worker restarts are for new code, not new PHP. Because your image is part of your supply chain, track its versions the way you track packages, as our guide to plugin and package supply chain security explains, and see our headless and custom website security guide for the wider picture. If you'd like a team to rebuild and redeploy for you, our emergency PHP patching service can help. Every PHP2Shell guide is in our PHP2Shell Resource Center.
Frequently Asked Questions
Is FrankenPHP affected by PHP2Shell?
Yes. PHP lists FrankenPHP among affected setups, and its advisory calls it "likely susceptible to application-independent attacks" for CVE-2026-109618. Use FrankenPHP 1.13.2 or later.
Which FrankenPHP version fixes PHP2Shell?
1.13.2, released 21 October 2026, and later versions. Version 1.13.3 (23 October) is a bug fix release on top of it.
Does restarting workers through the admin API apply the fix?
No. A worker restart re-runs your worker scripts in the same FrankenPHP process, with the same built-in PHP. Install the fixed binary or image and restart the process.
Can I update PHP inside FrankenPHP without updating FrankenPHP?
Not for the Docker images or static binaries, where PHP is built in. With the deb or rpm packages, PHP comes from separate php-zts packages, so a system update plus a service restart is the route.
Which static binary should I use if I need PHP 8.3 or 8.4?
The static binaries contain PHP 8.5 only. For another branch, use a Docker image tagged with that PHP version or the packages.
Is the worker-mode leak in 1.13.2 the same as PHP2Shell?
No. GHSA-4gfw-9v29-gp9h is a separate FrankenPHP issue in which some error data could carry over between requests on the same thread. Upgrading to 1.13.2 or later fixes both.
Put this into action with eSEOspace
We help businesses grow with maintenance & support that actually performs. Explore the services behind this guide:
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 →
Great — your audit is on the way!
We'll send your free SEO/GEO/AEO/CRO audit within the next few hours. Where should we send it?
You're all set! ✓
Your free audit is being prepared — check your inbox in the next few hours. Talk soon!
On this page
- Key Takeaways
- What PHP's Advisories Say About FrankenPHP
- Fixed FrankenPHP Releases
- How You Installed FrankenPHP Decides How You Update
- Updating Docker Images
- Updating the Static Binary or a Packaged Install
- Worker Mode: Why a Worker Restart Is Not Enough
- FrankenPHP's Own Fixes in 1.13.2
- How to Confirm You Are on a Fixed Build
- If You Can't Upgrade Today
- Conclusion
- Frequently Asked Questions





