CVE-2023-22727 (published 2023-01-17T21:15Z)

CakePHP is a development framework for PHP web apps. In affected versions the `Cake\\Database\\Query::limit()` and `Cake\\Database\\Query::offset()` methods are vulnerable to SQL injection if passed un-sanitized user request data. This issue has been fixed in 4.2.12, 4.3.11, 4.4.10. Users are advised to upgrade. Users unable to upgrade may mitigate this issue by using CakePHP's Pagination library. Manually validating or casting parameters to these methods will also mitigate the issue.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-89
cwe_name: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
description: The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/cakephp/cakephp
commit_details: repo_url: https://github.com/cakephp/cakephp
author: Mark Story
author_date: 2023-01-03 15:29:38-05:00
msg: Disallow strings in limit() and offset()

Back in 68a08a2 int casts were removed in limit() and offset(). This
opened up the possibility for applications to provide unsafe user input
into these methods and create an injection vector.

We've been trying to narrow the accepted types, so instead of adding
casting I've added an exception when strings that are not number shaped
are provided.
repository: repo_url: https://github.com/cakephp/cakephp
repo_name: cakephp/cakephp
description: CakePHP: The Rapid Development Framework for PHP - Official Repository
repo_language: PHP
owner: cakephp
file_changes: filename: Query.php
change_type: ModificationType.MODIFY
diff: @@ -1534,6 +1534,9 @@ class Query implements ExpressionInterface, IteratorAggregate
      */
     public function limit($limit)
     {
+        if (is_string($limit) && !is_numeric($limit)) {
+            throw new InvalidArgumentException('Invalid value for `limit()`');
+        }
         $this->_dirty();
         $this->_parts['limit'] = $limit;
 
@@ -1560,6 +1563,9 @@ class Query implements ExpressionInterface, IteratorAggregate
      */
     public function offset($offset)
     {
+        if (is_string($offset) && !is_numeric($offset)) {
+            throw new InvalidArgumentException('Invalid value for `offset()`');
+        }
         $this->_dirty();
         $this->_parts['offset'] = $offset;
 

programming_language: PHP
filename: QueryTest.php
change_type: ModificationType.MODIFY
diff: @@ -2218,6 +2218,32 @@ class QueryTest extends TestCase
         $this->assertCount(2, $result);
     }
 
+    /**
+     * Tests selecting rows with string offset/limit
+     */
+    public function testSelectLimitInvalid(): void
+    {
+        $query = new Query($this->connection);
+        $this->expectException(InvalidArgumentException::class);
+        $query->select('id')->from('comments')
+            ->limit('1 --more')
+            ->order(['id' => 'ASC'])
+            ->execute();
+    }
+
+    /**
+     * Tests selecting rows with string offset/limit
+     */
+    public function testSelectOffsetInvalid(): void
+    {
+        $query = new Query($this->connection);
+        $this->expectException(InvalidArgumentException::class);
+        $query->select('id')->from('comments')
+            ->offset('1 --more')
+            ->order(['id' => 'ASC'])
+            ->execute();
+    }
+
     /**
      * Tests selecting rows combining a limit and offset clause
      */

programming_language: PHP