highCVE-2026-57584Aug 28, 2026

CVE-2026-57584: Phalcon Router Catastrophic Backtracking (ReDoS)

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A nested quantifier in Phalcon's default MVC and CLI router patterns lets an unauthenticated attacker send a single ~40-byte HTTP request that pins a PHP worker at 100% CPU, taking down any default…

Packagephalcon/cphalcon
Ecosystemcomposer
Affected<= 5.14.2
Fixed in5.15.0
CVE-2026-57584: Phalcon Router Catastrophic Backtracking (ReDoS)

The problem

Every Phalcon MVC application using the default router (the normal case) registers a built-in route compiled to the PCRE pattern #^/([\w0-9\_\-]+)/([\w0-9\.\_]+)(/.*)*$#u. The trailing (/.*)* is a nested quantifier: the group body (/.*) overlaps itself because . matches /, creating an exponential number of backtracking paths when the anchor $ cannot be satisfied.

The same problem appears in four places: the default MVC route, the /:params placeholder expansion, the default CLI route, and the CLI /:params expansion. Router::handle() runs this match on every incoming request against the attacker-supplied URI, so no authentication or special route configuration is needed.

Proof of concept

A working proof-of-concept for CVE-2026-57584 in phalcon/cphalcon, with the exact payload below.

http
GET /a/a////////////////////////////////%0a%0a HTTP/1.1
Host: victim.example.com

PHP URL-decodes $_GET["_url"] (the default URI source), so %0a%0a arrives as two literal newline bytes. The . in (/.*)* does not match \n, and PCRE's $ forgives only one trailing newline, so two newlines force the match to fail. The engine then explores every possible partition of the leading run of slashes across the nested group, producing 2^(N/2) backtracking steps where N is the number of slashes.

The patch commits (14ba22d and fa798e9) replace (/.*)* with a possessive or atomic equivalent that eliminates backtracking ambiguity in all four emission sites: the MVC router constructor, Route::compilePattern(), the CLI router constructor, and Cli\Router\Route::compilePattern().

Removing the nested star prevents the engine from re-partitioning the slash run, capping complexity at O(N).

The fix

Upgrade to phalcon/cphalcon 5.15.0, which patches all four emission sites. No config workaround fully eliminates the risk: the default pcre.backtrack_limit caps the per-request CPU cost but still allows a volumetric DoS from concurrent requests, and lowering it does not fix the correctness bug where the default route silently fails to match.

Upgrade is the only complete fix.

Reported by nikkoenggaliano.

References: [1][2][3][4][5][6]

Related research