Cloud · DevOps · PHP Security · Web Runtimes

FrankenPHP 1.13.5: patch uploaded-file execution safely

FrankenPHP 1.13.5 fixes 17 vulnerabilities. Triage upload and worker exposure, rebuild immutable images, verify routes and review evidence safely.

TOPIC HUBCloud, DevOps & Kubernetes
A technician using a laptop beside a server rack, representing a controlled FrankenPHP security upgrade and verification workflow
D

FrankenPHP 1.13.5 is a security release that fixes 17 vulnerabilities. The highest-severity issue can make an uploaded non-PHP file execute as PHP when a crafted path causes the PHP server's route and path-splitting logic to disagree. If you operate FrankenPHP 1.13.4 or earlier, rebuild every image on 1.13.5, keep uploads outside the document root, replace every running instance, and verify routing and worker isolation before declaring the patch complete.

The official 1.13.5 release was published on November 5, 2026. This guide separates what the maintainers documented from engineering recommendations for platform teams. The official advisories include proof-of-concept material, but the cited project sources do not report active exploitation or a confirmed compromise. An observed probe is not proof that code executed.

Answer first

Treat this as an urgent exposure-driven update, not a reason to test exploit payloads against production. The shortest defensible path is:

  1. inventory the exact FrankenPHP version and image digest on every node, pod and container;
  2. move or confirm user-controlled uploads outside the web document root;
  3. rebuild immutable artifacts with FrankenPHP 1.13.5 or later;
  4. replace all instances, including long-running workers;
  5. verify invalid script paths return 404, upload routes remain static, PHP source is never served, and request state cannot cross worker boundaries;
  6. retain rollout evidence and review suspicious historical requests without equating attempts with compromise.

What the official sources establish

The maintainers describe FrankenPHP 1.13.5 as a security release addressing 17 vulnerabilities. The release also updates bundled components to Caddy 2.11.9 and Mercure 1.1.6 and strongly recommends upgrading.

The highest-severity advisory, GHSA-j99q-3wr8-xj43, affects FrankenPHP through 1.13.4 and is fixed in 1.13.5. It documents a path confusion condition in php_server: when an attacker can place a chosen file or path under the document root, a request containing a crafted PHP-looking path segment can cause a later non-PHP file to be selected and executed as PHP. The patched handler rejects an invalid script path with 404. The advisory assigns CVSS 7.5 and does not assign a CVE.

Two related advisories matter to worker deployments:

  • GHSA-v7hf-4gqv-hf8p affects versions 1.8.0 through 1.13.4. A configuration combining a worker match rule with the built-in file server can expose PHP source instead of executing it. Version 1.13.5 fixes the issue.
  • GHSA-8qcf-v46r-g2mc affects versions through 1.13.4. Under specific application patterns, output, headers or cookies generated late by a previous request can leak into the next request handled by the same worker. The advisory says classic mode is not affected.

The release includes additional fixes for open redirects, Host handling, slow request bodies, routing-rule bypasses and crashes. This article focuses on the three issues most likely to change deployment and verification work.

Documented fact: the project published advisories and a fixed release. Maintainer claim: the release resolves the listed issues and should be installed. Engineering analysis: your real priority depends on whether an attacker can write beneath the document root, whether php_server receives upload paths, and whether worker-specific configuration or lifecycle behavior is present.

Exposure decision table

Runtime conditionPriorityImmediate action
FrankenPHP 1.13.4 or earlier and user-controlled files can land under the document rootCritical operational priorityIsolate uploads, restrict routing, rebuild on 1.13.5, and review request plus process evidence
php_server is reachable but uploads are stored outside the document rootHighUpgrade promptly and verify no alternate import, cache or extraction path writes into the root
Worker mode uses match together with the built-in file serverHighUpgrade; until then disable the file server for that path or remove the risky match pattern
Worker mode may emit destructor, error-handler or garbage-collection output after a responseHigh for confidentialityUpgrade, rotate affected workers, and test cross-request isolation
Classic mode only, with no attacker-controlled file placementStill patchThe worker leak does not apply, but the main routing issue and other 1.13.5 fixes still require review
Version and configuration cannot be provedTreat as exposedStop guessing: capture runtime version, image digest and effective Caddy configuration
Patch evidence should connect the runtime version, immutable image, effective routes, worker lifecycle and negative verification tests.
Patch evidence should connect the runtime version, immutable image, effective routes, worker lifecycle and negative verification tests. Open for a larger view

Find every running copy

An image tag in a repository is not runtime evidence. Query the executable inside each live unit and pair the result with the deployed image identifier.

For a standalone host:

frankenphp version
systemctl status frankenphp --no-pager
systemctl cat frankenphp

For Docker, record both the image reference and the version reported in the container:

docker inspect --format '{{.Config.Image}} {{.Image}}' <container>
docker exec <container> frankenphp version

For Kubernetes, collect image references and immutable image IDs, then verify the binary in representative pods from every workload and revision:

kubectl get pods -A -o custom-columns='NS:.metadata.namespace,POD:.metadata.name,IMAGE:.spec.containers[*].image,IMAGE_ID:.status.containerStatuses[*].imageID'
kubectl exec -n <namespace> <pod> -- frankenphp version

Also search CI base images, Helm values, Compose files, systemd units, PaaS buildpacks, disaster-recovery templates and dormant replicas. A fixed primary deployment with a vulnerable rollback image remains an incomplete remediation.

Contain before the rebuild

The main advisory's strongest compensating control is architectural: store uploads outside the document root. If the application must serve them, use a static route or object-storage origin that cannot enter the PHP handler.

Until the rollout finishes:

  • block writes to the document root except from the build/release process;
  • route upload prefixes directly to static storage, never through php_server;
  • reject suspicious nested PHP-looking path segments and unusual encoded separators at the edge, while testing legitimate routes;
  • disable extraction of untrusted archives into any served directory;
  • for the source-disclosure condition, use file_server off on the affected worker route or remove the risky worker match configuration, as the advisory recommends;
  • increase monitoring for unexpected PHP child behavior, outbound connections and file changes.

These are temporary controls. They do not replace the fixed release, and file_server off addresses the documented source-disclosure configuration rather than every issue in 1.13.5.

Upgrade as an immutable replacement

  1. Freeze the baseline. Save the current image digest, frankenphp version, effective Caddy configuration, environment inventory and representative health results.
  2. Update the build. Select an official FrankenPHP 1.13.5-or-later artifact compatible with your PHP extensions. Pin the resolved digest in production rather than relying only on a mutable tag.
  3. Rebuild dependencies. Recreate the application image, extensions and operating-system packages; do not copy the old FrankenPHP binary or Caddy module directory into the new layer.
  4. Scan and attest. Generate an SBOM, run the organization's image scanner, and verify the source and signature or provenance mechanism available in your supply chain.
  5. Canary safely. Send controlled traffic to a small set of new instances. Exercise uploads, front-controller routes, worker endpoints, cache behavior and authentication without using the public exploit proof.
  6. Replace, do not merely reload. Terminate old containers and long-running workers so no pre-fix process survives. Confirm every pod, node and rollback revision reports the fixed version and intended digest.
  7. Promote with evidence. Attach the digest, version output, config hash, test results and rollout timestamps to the change record.

The 1.13.5 release notes say Caddy is updated to 2.11.9. If your build compiles a custom FrankenPHP/Caddy binary, confirm the final executable actually contains the intended component set rather than assuming the base tag did the work.

Verification without weaponizing production

Use negative routing tests and controlled fixtures:

TestExpected result on the fixed deployment
Request an invalid or nonexistent script path with extra path information404; no fallback to a non-PHP file
Upload a harmless text fixture through the normal application pathStored outside the document root and served only as static content
Request a PHP source filename through worker and static-file routesSource is never returned
Send two marked requests through the same worker while triggering normal cleanupNo header, cookie or body marker crosses to the next response
Send an unknown Host value allowed by your test environmentRequest is rejected or routed only according to the intended host policy
Slowly stream a request body in a staging testTimeouts and concurrency controls prevent one client from exhausting all PHP threads
Restart and scale the workloadEvery replacement reports 1.13.5 or later and the approved image digest

Run the same checks from the public ingress and from an internal service path because proxies can rewrite the URI, Host or path information. Capture status, response headers and server logs. Do not upload executable PHP payloads or replay public proofs against production.

Historical review: attempts are not compromise

Search access and WAF logs for nested .php path segments, repeated path-info variants, encoded separators, unusual Unicode around script suffixes, upload paths followed by execution-like requests, and successful responses where a non-PHP object should have been static. Correlate those requests with:

  • file-creation and integrity logs beneath the document root;
  • PHP, Caddy and application error logs;
  • process trees and unexpected child processes;
  • outbound DNS and network connections;
  • secrets access, authentication changes and persistence indicators.

A matching URL is evidence of a probe. A 200 response is stronger but still not conclusive. Confirm execution through process, application, filesystem or network evidence. If compromise is plausible, preserve volatile evidence, rotate exposed secrets from a trusted environment, rebuild from known-good sources and follow the incident-response plan.

Best practices

  • Keep uploaded and generated files outside the executable document root.
  • Make runtime version and image digest observable in deployment inventory.
  • Treat the effective Caddyfile as a controlled, reviewable artifact.
  • Use least-privilege filesystem permissions for the FrankenPHP process.
  • Bound request-body time and size at both ingress and application layers.
  • Give worker-mode applications explicit lifecycle, cleanup and isolation tests.
  • Keep a tested rollback artifact that is also patched.

Anti-patterns and limits

Do not declare remediation complete because a Dockerfile changed, a tag says “latest,” one pod restarted, or a WAF rule blocked one example path. Do not use exploit success as the production acceptance test. Do not infer compromise solely from a scanner finding, and do not infer safety from the absence of matching access-log strings.

The advisories describe software behavior, not your entire application. Framework routing, reverse proxies, archive extraction, mounted volumes, custom Caddy modules and worker code can add exposure not covered by a default configuration. Conversely, storing all user content outside the document root reduces the main precondition but does not remove the need to install the other security fixes in 1.13.5.

Executive checklist

  • [ ] Every live and rollback instance is inventoried by version and digest.
  • [ ] No user-controlled file can be written under the document root.
  • [ ] Build artifacts use FrankenPHP 1.13.5 or later.
  • [ ] All old containers and workers were replaced.
  • [ ] Invalid script paths return 404.
  • [ ] Upload routes cannot enter the PHP handler.
  • [ ] Worker routes never expose PHP source.
  • [ ] Cross-request headers, cookies and body output are isolated.
  • [ ] Public-ingress and internal-path tests passed.
  • [ ] Historical probes were separated from confirmed execution evidence.
  • [ ] Rollout evidence is retained with the change record.

For adjacent response patterns, see the PHP2Shell patch guide, the Next.js 16.4.1 critical RCE guide, and the Babelfish TDS vulnerability guide. The services page connects these controls to platform, cloud and product engineering work.

References

  1. FrankenPHP 1.13.5 release
  2. GHSA-j99q-3wr8-xj43: uploaded non-PHP file can be executed as PHP
  3. GHSA-v7hf-4gqv-hf8p: PHP source disclosure with worker match and file server
  4. GHSA-8qcf-v46r-g2mc: output from a previous worker request can leak
  5. FrankenPHP worker mode documentation
  6. FrankenPHP configuration documentation
  7. Derrick Coetzee, “Technician with laptop working on server rack at NERSC,” CC0 1.0, Wikimedia Commons

Prepared by: Noor Yasser

Official references

These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.

Prepared by: Noor Yasser

FROM DECISION TO DELIVERY

Working through a similar engineering challenge?

I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.

Book a 30-minute callRelated serviceBackend engineering & API integrationsRelevant projectLogistics at scale