CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-24895

FrankenPHP Path Confusion: When 'Ⱥ' Becomes 'ⱥ' and Your Server Explodes

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 12, 2026·6 min read·68 visits

Executive Summary (TL;DR)

FrankenPHP < 1.11.2 mishandles Unicode case conversion in URLs. Because some characters change byte length when lowercased (e.g., 'Ⱥ' -> 'ⱥ'), the server miscalculates where the file path ends. Attackers can use this to execute arbitrary files (RCE). Update to 1.11.2 immediately.

A critical path confusion vulnerability in FrankenPHP's CGI handler allows attackers to execute arbitrary files as PHP scripts. The flaw stems from a mismatch in byte length when converting Unicode characters to lowercase, causing the server to miscalculate the boundary between the script path and path info. By injecting specific characters like 'Ⱥ', attackers can offset the internal pointer and trick the server into executing malicious uploads (e.g., images or text files) as code.

The Hook: Frankenstein's Monster

FrankenPHP is a modern, high-performance application server for PHP, built on top of the Caddy web server and written in Go. It’s a beautiful amalgamation of technologies designed to modernize the PHP ecosystem. But as with any complex machinery, the devil is in the details—specifically, in how it handles the Common Gateway Interface (CGI) logic.

To serve a PHP request, the server needs to know two things: which file is the script (SCRIPT_FILENAME) and what comes after it (PATH_INFO). This is usually determined by splitting the request URL at the file extension (e.g., .php). It sounds simple, like cutting a sandwich in half.

However, in CVE-2026-24895, we discover that FrankenPHP was using a rusty knife. By assuming that a string's length remains constant when converted to lowercase, the developers inadvertently opened a door for attackers to slide malicious payloads right past the bouncer. This isn't just a parsing error; it's a logic flaw that turns a harmless file upload mechanism into a full-blown Remote Code Execution (RCE) vector.

The Flaw: The Unicode expansion Trap

The root cause of this vulnerability is a classic "byte vs. character" confusion in Go. The vulnerable code attempted to find the file extension in a URL by first converting the entire path to lowercase and then searching for the extension index. The fatal flaw? Case folding in UTF-8 is not length-invariant.

Consider the character Latin Capital Letter A with Stroke ('Ⱥ', U+023A). In UTF-8, this character takes up 2 bytes (0xC8 0xBA). However, when you run this through Go's strings.ToLower(), it converts to Latin Small Letter A with Stroke ('ⱥ', U+2C65). Here's the kicker: the lowercase version takes up 3 bytes (0xE2 0xB1 0xA5).

For every 'Ⱥ' in the URL, the lowercased string grows by 1 byte. FrankenPHP calculated the split index based on this longer lowercased string but applied that index to the shorter original string. It’s like measuring a distance on a zoomed-in map and then walking that distance in the real world—you’re going to overshoot your destination.

The Code: The Smoking Gun

Let's look at the logic that caused the meltdown. The function splitPos was responsible for finding where the script name ends.

The Vulnerable Logic (Simplified):

// BAD: Lowercase the whole path first
lowerPath := strings.ToLower(path)
// Find ".php" in the lowercased version
index := strings.Index(lowerPath, ".php")
// Use that index to slice the ORIGINAL path
scriptName := path[:index]

If path is /Ⱥ.php, lowerPath is /ⱥ.php. The index of .php in the lowercased string is shifted because ⱥ is longer. When that shifted index is applied to the original string, it slices at the wrong byte.

The Fix (Commit 04fdc0c1): The patch completely removes the global strings.ToLower call. Instead, it iterates through the string byte-by-byte. If it sees ASCII, it does a cheap case-insensitive check. If it sees Unicode (bytes >= utf8.RuneSelf), it switches to the golang.org/x/text/search package, which correctly handles offsets without distorting the source string length.

// GOOD: Iterate and handle ASCII/Unicode separately
for i := 0; i < len(path); i++ {
    // ... ASCII checks ...
    if c >= utf8.RuneSelf {
        // Use a matcher that respects original indices
        start, _ := matcher.IndexString(path[i:])
        // ...
    }
}

The Exploit: Shifting Reality

To exploit this, an attacker needs to perform a "Path Confusion" attack. The goal is to upload a file (e.g., shell.txt containing PHP code) and then access it via a URL that tricks FrankenPHP into executing it as a PHP script.

The Setup:

  1. Attacker uploads shell.txt containing <?php system($_GET['cmd']); ?> to /uploads/.
  2. The server usually prevents executing .txt files as PHP.

The Attack: The attacker requests: GET /ȺȺȺȺshell.php.txt.php

Here is the math of the madness:

  • Original String: /ȺȺȺȺshell.php.txt.php
    • Prefix ȺȺȺȺ: 4 chars * 2 bytes = 8 bytes.
  • Lowercased String: /ⱥⱥⱥⱥshell.php.txt.php
    • Prefix ⱥⱥⱥⱥ: 4 chars * 3 bytes = 12 bytes.
    • Difference: +4 bytes.

FrankenPHP searches the lowercased string for .php. It finds it at the end. Because of the expansion, the index returned is 4 bytes larger than it would be in the original string. When the server applies this index to the original string, the slice point moves forward by 4 bytes, effectively "skipping" characters.

By carefully aligning the number of 'Ⱥ' characters, the attacker shifts the split point so that SCRIPT_FILENAME resolves to /uploads/shell.txt (or similar), while the routing logic—confused by the extension check—hands it off to the PHP engine. The engine executes the text file, and you have RCE.

The Impact: Why You Should Care

This is a High Severity (CVSS 8.9) vulnerability for a reason. It requires no authentication, no special privileges, and no user interaction. It purely relies on the server's configuration allowing file uploads or having existing files that can be misinterpreted.

If you are running FrankenPHP in a Docker container or a standard deployment exposed to the web, an attacker can potentially:

  1. Execute Code: Run arbitrary commands on the server.
  2. Bypass Access Controls: Access files that should be protected by extension allowlists.
  3. Lateral Movement: Use the compromised server to attack internal networks (database, Redis, etc.).

It effectively turns any file upload feature—even one that strictly validates extensions like .png or .txt—into a backdoor.

The Fix: Stop The Bleeding

If you are running FrankenPHP, check your version immediately. If it is less than 1.11.2, you are vulnerable.

Remediation:

  1. Upgrade: Pull the latest Docker image or binary (v1.11.2 or later).
    • docker pull dunglas/frankenphp
  2. WAF Rules: If you cannot patch immediately, configure your WAF to block requests containing the character 'Ⱥ' (%C8%BA) or other expanding Unicode characters in the URL path. However, be aware that many Unicode characters can trigger expansion or contraction, so a blacklist is fragile.

This vulnerability serves as a stark reminder: never rely on string transformations (like lowercasing) for indexing if the transformation isn't length-preserving. Always validate indices against the original source of truth.

Official Patches

FrankenPHPGitHub Commit: Fix path splitting logic
FrankenPHPRelease v1.11.2

Fix Analysis (1)

Technical Appendix

CVSS Score
8.9/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P

Affected Systems

FrankenPHP < 1.11.2

Affected Versions Detail

Product
Affected Versions
Fixed Version
FrankenPHP
php
< 1.11.21.11.2
AttributeDetail
CWE IDCWE-180
Attack VectorNetwork
CVSS Score8.9 (High)
ImpactRemote Code Execution (RCE)
Exploit StatusPoC Available
Bug ClassPath Confusion / Byte Index Misalignment

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1036Masquerading
Defense Evasion
CWE-180
Incorrect Behavior Order: Validate Before Canonicalize

Incorrect Behavior Order: Validate Before Canonicalize

Known Exploits & Detection

GitHub AdvisoryProof of concept URI using 'Ⱥ' expansion.

Vulnerability Timeline

Fix commit authored by Kévin Dunglas
2026-01-26
CVE-2026-24895 Published
2026-02-12
FrankenPHP v1.11.2 Released
2026-02-12

References & Sources

  • [1]GHSA-g966-83w7-6w38
  • [2]CWE-180

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•CVE-2026-54348
7.2

CVE-2026-54348: Second-Order SQL Injection in Froxlor API Layer

An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.

Amit Schendel
Amit Schendel
0 views•6 min read
•about 2 hours ago•CVE-2026-54543
5.4

CVE-2026-54543: DNS Resource Record (RR) Injection in Froxlor DomainZones API

CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.

Amit Schendel
Amit Schendel
2 views•7 min read
•about 2 hours ago•CVE-2026-42533
9.2

CVE-2026-42533: NGINX Map Directive and Regex Matching Pre-Auth Heap Buffer Overflow & Info Leak

CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.

Alon Barad
Alon Barad
5 views•7 min read
•about 3 hours ago•CVE-2026-55593
6.5

CVE-2026-55593: Persistent Administrative Hijacking via Cross-Site Request Forgery in Froxlor Ajax Router

Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.

Amit Schendel
Amit Schendel
2 views•8 min read
•about 4 hours ago•CVE-2026-62988
9.0

CVE-2026-62988: Multi-Factor Authentication and Credential Bypass in Froxlor API

An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 5 hours ago•CVE-2026-70666
7.4

CVE-2026-70666: Server-Side Request Forgery in Netflix Lemur ACME Authority Management

CVE-2026-70666 is a critical Server-Side Request Forgery (SSRF) vulnerability in Netflix Lemur's ACME certificate management integration. Prior to version 1.9.3, the system allowed authority-role users to bypass initial ACME URL allowlist validations when updating an existing authority. Additionally, the underlying ACME network client blindly parsed and connected to dynamic endpoint URLs supplied in JSON responses from the configured ACME directory, allowing attackers to route arbitrary JWS-signed requests to internal services or cloud metadata endpoints.

Alon Barad
Alon Barad
4 views•5 min read