Caddy (FastCGI), Unicode Path Matching Bypass, CVE (pending) (High)

Listen to this Post

The vulnerability resides in Caddy’s FastCGI transport function `splitPos()` inside modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go. It misuses `golang.org/x/text/search` with `search.IgnoreCase` when the request path contains a non‑ASCII byte. Two distinct flaws allow an attacker to trick Caddy into treating a non‑.php file as a script, leading to remote code execution if the attacker can place content into a file served via FastCGI (e.g., uploads).

Flaw 1 – Stale `match` after fallback

When the inner `for j` loop encounters a byte c >= utf8.RuneSelf, it calls splitSearchNonASCII.IndexString(). If that returns -1, the loop `break`s without setting match = false. The outer code then sees `match` still `true` and returns i + splitLen, incorrectly treating the file as a script even though no valid extension matched.

Flaw 2 – Unicode equivalence folding

`search.New(language.Und, search.IgnoreCase)` performs full Unicode case‑folding and compatibility decomposition. Many non‑ASCII characters (e.g., fullwidth dot ., mathematical bold 𝗽, etc.) fold onto ASCII ., p, h, p. Thus a path containing `.php` or `.𝗽𝗵𝗽` is reported as .php, bypassing the intended ASCII‑only extension check.
Both flaws share the same root cause: invoking a Unicode‑aware search on an ASCII‑only, lower‑cased `SplitPath` entry while the path contains non‑ASCII bytes. Because `Provision()` guarantees split entries are ASCII, any non‑ASCII byte in the path can never be part of a legitimate match – yet the fallback incorrectly assumes it can.

dailycve form:

Platform: Caddy
Version: < fixed (commit 4ddad83c)
Vulnerability: RCE via split_path bypass
Severity: High (8.1)
date: 2026-05-18

Prediction: Patch already released (2026-05-17)

What Undercode Say:

Test for flaw 1 – file with non‑ASCII byte .¡.txt
curl -i --path-as-is "http://127.0.0.1:8080/poc-match-unset.%C2%A1.txt/trigger"
Test for flaw 2 – Unicode lookalike .𝗽𝗵𝗽
curl -i --path-as-is "http://127.0.0.1:8080/poc-search-norm.%F0%9D%97%BD%F0%9D%97%B5%F0%9D%97%BD.anything/trigger"
Check if a normal .txt file is NOT routed to PHP (should 404)
curl -i --path-as-is "http://127.0.0.1:8080/poc-match-unset.txt/trigger"

How Exploit:

Place a file with a crafted name (e.g., `poc-match-unset.¡.txt` containing <?php system($_GET['cmd']); ?>) in a publicly writable directory. Send a request with the URL‑encoded non‑ASCII byte or Unicode lookalike sequence, appended with /trigger. Caddy’s `splitPos()` returns a position inside the non‑.php filename, causing FastCGI to execute it as PHP.

Protection from this CVE:

Update Caddy to commit `4ddad83c` or any release containing the patch. The fix removes the `golang.org/x/text/search` fallback entirely and treats any `byte >= utf8.RuneSelf` as a non‑match. As a workaround, avoid serving user‑uploaded files via FastCGI or use strict path validation at the web application level.

Impact:

Remote code execution (RCE) on the FastCGI upstream (e.g., PHP‑FPM). Precondition: attacker can upload or control a file whose name contains a non‑ASCII byte or Unicode lookalike of .php. Common in file upload endpoints, content stores, or package mirrors. CVSS 8.1 (High).

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top