{"record":{"id":"54d2c3a544447e8a","repo":"cakephp/cakephp","slug":"passing-extra-expressions-by-associative-array-s-s-is-not","errorCode":null,"errorMessage":"Passing extra expressions by associative array (`'%s' => '%s'`) is not allowed to avoid potential SQL injection. Use QueryExpression or numeric array instead.","messagePattern":"Passing extra expressions by associative array \\(`'(.+?)' => '(.+?)'`\\) is not allowed to avoid potential SQL injection\\. Use QueryExpression or numeric array instead\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Database/Expression/OrderByExpression.php","lineNumber":78,"sourceCode":"    /**\n     * Auxiliary function used for decomposing a nested array of conditions and\n     * building a tree structure inside this object to represent the full SQL expression.\n     *\n     * New order by expressions are merged to existing ones\n     *\n     * @param array $conditions list of order by expressions\n     * @param array $types list of types associated on fields referenced in $conditions\n     * @return void\n     */\n    protected function _addConditions(array $conditions, array $types): void\n    {\n        foreach ($conditions as $key => $val) {\n            if (\n                is_string($key) &&\n                is_string($val) &&\n                !in_array(strtoupper($val), ['ASC', 'DESC'], true)\n            ) {\n                throw new InvalidArgumentException(\n                    sprintf(\n                        \"Passing extra expressions by associative array (`'%s' => '%s'`) \" .\n                        'is not allowed to avoid potential SQL injection. ' .\n                        'Use QueryExpression or numeric array instead.',\n                        $key,\n                        $val,\n                    ),\n                );\n            }\n        }\n\n        $this->_conditions = array_merge($this->_conditions, $conditions);\n    }\n}\n","sourceCodeStart":60,"sourceCodeEnd":93,"githubUrl":"https://github.com/cakephp/cakephp/blob/1128eba9b09f1946df684811350e26f2cef68fac/src/Database/Expression/OrderByExpression.php#L60-L93","documentation":"OrderByExpression rejects associative arrays where both key and value are strings and the value is not ASC/DESC, because generating `ORDER BY key value` from arbitrary string pairs could inject SQL. Only explicit QueryExpression objects or numeric arrays of expressions are allowed for complex ordering.","triggerScenarios":"Calling ->orderBy(['field' => 'some_function(other)']) or ->order(['name' => 'custom sql']) with a non-ASC/DESC string value.","commonSituations":"Migrating old code that relied on ordering by raw SQL snippets in associative arrays; users passing dynamic sort definitions from request input; version upgrades (CakePHP 4.3+/5) that hardened this API.","solutions":["Use an expression: ->orderBy($query->newExpr('FIELD(name)')) or a QueryExpression","Use 'ASC'/'DESC' as the value if that was the intent","Build ordering from a numeric array of expression objects instead of a string-keyed map"],"exampleFix":"// before\n$query->orderBy(['name' => 'LOWER(name)']);\n// after\n$query->orderBy([$query->newExpr('LOWER(name)')]);","handlingStrategy":"validation","validationCode":"foreach ($order as $k => $v) { if (is_string($k) && is_string($v) && !in_array(strtoupper($v), ['ASC','DESC'], true)) { throw new \\InvalidArgumentException('Use an expression for custom ordering'); } }","typeGuard":"function isValidOrderValue(mixed $v): bool { return is_string($v) && in_array(strtoupper($v), ['ASC','DESC'], true); }","tryCatchPattern":"try { $query->sql(); } catch (\\InvalidArgumentException $e) { if (str_contains($e->getMessage(), 'Passing extra expressions')) { /* rebuild order with expressions */ } }","preventionTips":["Only use 'ASC'/'DESC' as associative-array order values","Wrap custom ordering in newExpr()/QueryExpression","Whitelist sortable columns from user input"],"tags":["cakephp","sql-injection","order-by","query-builder"],"backgroundTag":"invalid-argument-value","analyzedSha":"1128eba9b09f1946df684811350e26f2cef68fac","analyzedAt":"2026-09-12T12:07:00.388Z","contentChangedAt":"2026-09-12T12:07:00.388Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}