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-63221

CVE-2026-63221: SQL Injection in CodeIgniter4 Query Builder deleteBatch()

Amit Schendel
Amit Schendel
Senior Security Researcher

Aug 8, 2026·8 min read·1 visit

Executive Summary (TL;DR)

CodeIgniter4 versions 4.3.0 through 4.7.3 contain an SQL injection flaw in the Query Builder's deleteBatch() component. When WHERE clauses are chained before a batch delete operation, the system fails to escape bound values, leading to unauthenticated SQL injection.

An SQL injection vulnerability exists in the Query Builder component of the CodeIgniter4 full-stack PHP framework. The vulnerability is located within the compilation logic of the batch delete operation, deleteBatch(). When an application chains where() conditions prior to calling deleteBatch(), the Query Builder fails to enforce or respect the escaping flags of the parameters bound to the WHERE clauses. Instead of passing these parameters through the database driver standard escaping logic, the compilation engine interpolates the raw, unescaped bound values directly into the compiled SQL string, allowing remote attackers to execute arbitrary SQL commands.

Vulnerability Overview

The CodeIgniter4 Query Builder provides an object-oriented interface for generating database queries. A specific design pattern within web applications involves batch processing, where records are updated or deleted in groups using helper methods such as deleteBatch(). To optimize execution, these methods accept arrays of data and combine them with standard Query Builder state filters, including chained where() clauses.

The vulnerability, identified as CVE-2026-63221, resides in how these state filters are combined with the final query. When standard Query Builder filters are applied before a deleteBatch() execution, the database compiler triggers a separate compilation pipeline. Instead of binding these parameters securely or routing them through standard query parametrization interfaces, the database-specific builder classes attempt to manually compile the final SQL string.

This manual compilation leads to a vulnerability class known as improper neutralization of special elements used in an SQL command, classified under CWE-89. The query compilation logic bypasses the active database driver escaping mechanism for filters assigned via standard where clauses. As a result, user-controlled input designed to act as a data value can break out of the SQL syntax context and execute arbitrary database operations.

Root Cause Analysis

To understand the root cause of the flaw, it is necessary to examine how CodeIgniter's Query Builder manages parameter state. When a developer registers a condition using $builder->where('field', $value), the framework generates an internal binding entry. This entry is represented inside the $this->binds associative array, where the key represents the parameter identifier and the value is a indexed array containing two elements: the actual bound value ($bind[0]) and a boolean escape flag ($bind[1]). The escape flag indicates whether the database driver must sanitize and wrap the value in quotes prior to compilation.

In standard SQL compilation paths, such as those executed during a typical delete() or select() operation, the compiler processes this array sequentially and applies driver-specific escaping rules to any bind where the escape flag is active. However, when performing batch deletions, the compilation path diverges. The framework uses driver-specific compilers, such as the _deleteBatch() method located in the core BaseBuilder.php class, as well as dedicated files for drivers like Oracle (OCI8) and PostgreSQL.

Within these batch compilation routines, the framework merges the batch-specific constraints with any prior where conditions. In versions 4.3.0 through 4.7.3, this merge operation was handled by a nested loop that performed a direct string replacement on the query placeholders. The loop extracted the value element directly from the $this->binds array and ran str_replace on the SQL condition template. This replacement completely ignored the state of the escape flag stored in $bind[1] and did not route the raw value through the database connection's character escaping routines. Consequently, the literal unescaped string was embedded directly into the executable query.

Code Analysis

An analysis of the vulnerable source code in system/Database/BaseBuilder.php reveals the exact point where parameter isolation fails. The following snippet illustrates the naive loop implementation before the vulnerability was patched:

// system/Database/BaseBuilder.php (Vulnerable implementation in versions < 4.7.4)
protected function _deleteBatch(string $table, array $keys, array $values): string
{
    // ... [Batch query syntax initialization] ...
 
    // convert binds in where
    foreach ($this->QBWhere as $key => $where) {
        foreach ($this->binds as $field => $bind) {
            // VULNERABILITY: Direct string replacement. $bind[0] contains the raw value.
            // $bind[1] (the escaping boolean) is completely ignored in this iteration.
            $this->QBWhere[$key]['condition'] = str_replace(':' . $field . ':', $bind[0], $where['condition']);
        }
    }
 
    $sql .= ' ' . $this->compileWhereHaving('QBWhere');
    // ...
}

The patch introduced in CodeIgniter 4.7.4 refactors this process. It introduces a dedicated helper method named convertWhereBindsForBatch() which checks the escape flag and utilizes the underlying database connection's escaping capability:

// system/Database/BaseBuilder.php (Patched implementation in version 4.7.4)
protected function _deleteBatch(string $table, array $keys, array $values): string
{
    // ...
    // convert binds in where
    // FIX: Replaced loop with a secure, centralized escaping helper
    $this->convertWhereBindsForBatch();
 
    $sql .= ' ' . $this->compileWhereHaving('QBWhere');
    // ...
}
 
/**
 * Escapes and substitutes the WHERE binds into the QBWhere conditions
 * for batch delete queries.
 */
protected function convertWhereBindsForBatch(): void
{
    $replacers = [];
 
    foreach ($this->binds as $field => $bind) {
        // FIX: The database driver escape() method is called if the escape flag ($bind[1]) is true.
        $escapedValue = $bind[1] ? $this->db->escape($bind[0]) : $bind[0];
 
        if (is_array($bind[0])) {
            $escapedValue = '(' . implode(',', $escapedValue) . ')';
        }
 
        $replacers[':' . $field . ':'] = (string) $escapedValue; // Safe string casting
    }
 
    // FIX: Using strtr() with pre-populated mapping avoids vulnerable double-replacement scenarios.
    foreach ($this->QBWhere as $key => $where) {
        $this->QBWhere[$key]['condition'] = strtr($where['condition'], $replacers);
    }
}

By delegating parameter substitution to convertWhereBindsForBatch(), the system ensures that values containing single quotes or other SQL control characters are safely formatted. For instance, single quotes are doubled up or backslash-escaped according to the specific rules of the database driver in use. Additionally, the replacement mechanism was switched from a nested loop using str_replace to a single-pass strtr function. This prevents double-substitution attacks where an attacker crafts input containing synthetic placeholders to manipulate subsequent replacement steps.

Exploitation Methodology

Exploitation of CVE-2026-63221 requires an endpoint that processes user input and chains it to a query builder context before a batch delete operation. A typical vulnerable pattern occurs in administrative bulk data purges or session clearouts.

Consider a target application processing request parameters to filter batch deletions:

// Example of vulnerable application logic
public function bulkDeleteLogs() 
{
    $filter = $this->request->getPost('filter_value');
    $batchData = [
        ['log_id' => 12,
         'archive_status' => 'pending'],
        ['log_id' => 13,
         'archive_status' => 'pending']
    ];
 
    $builder = $this->db->table('system_logs');
    $builder->setData($batchData, null, 'data')
            ->onConstraint(['log_id' => 'log_id'])
            ->where('log_type', $filter) // Unescaped user input
            ->deleteBatch();
}

If an attacker submits a payload structured to alter the syntax logic, the unescaped interpolation inserts the string verbatim. For instance, the attacker provides the payload ' OR 1=1 --. The Query Builder parses the where condition and compiles the target query. Because the replacement logic uses direct string substitution, the compiled SQL string outputs the following syntax:

DELETE FROM "system_logs" WHERE "system_logs"."log_type" = '' OR 1=1 --' AND "system_logs"."log_id" IN (12, 13)

When processed by the database engine, the OR 1=1 clause evaluates to true for every row in the database table. The SQL comment syntax (--) truncates the remaining constraints generated by the batch processor. As a consequence, the DBMS executes a full table deletion, removing all logs and causing a localized denial of service and loss of database integrity.

Impact Assessment

The impact of CVE-2026-63221 is rated as Critical, with a CVSS v3.1 base score of 9.4. Although the vulnerability resides within a batch delete operation rather than a select operation, the security implications are severe. The primary impact is to system integrity and availability, as unauthorized database modifications can occur without authentication.

In standard configurations, an attacker can exploit this SQL injection vulnerability to destroy arbitrary tables, manipulate administrative user tables, or bypass application constraints. Depending on the underlying database engine and the system's execution privileges, stacked query capabilities could allow the execution of secondary SQL statements. For databases like PostgreSQL or Microsoft SQL Server, this could lead to remote execution of OS commands via system functions (such as xp_cmdshell or external language bindings).

Additionally, because the vulnerability allows the injection of SQL functions, attackers can perform blind, time-based SQL injection to exfiltrate database contents. By substituting data values with conditional evaluation functions (like pg_sleep()), the attacker can read sensitive configuration keys, password hashes, or application records character-by-character based on database response delays.

Remediation and Mitigation

The most secure remediation for this vulnerability is to upgrade the application framework to CodeIgniter version 4.7.4 or later. This release completely addresses the parsing flow in the standard query compiler and driver-specific subclasses.

If upgrading the framework is not immediately possible due to dependency constraints, you can manually apply the patch by editing the base database class. Open system/Database/BaseBuilder.php and locate the _deleteBatch method. Replace the naive foreach loop that performs the str_replace operations with the implementation of convertWhereBindsForBatch() as outlined in the patch analysis.

In addition to upgrading, developers must review applications for unsafe query builder state chaining. As a general security measure, avoid passing raw, unvalidated input directly to Query Builder state methods. Utilize strict input validation schemas (such as alphanumeric regex filters or predefined allowlists) to ensure that only expected query criteria are processed by the database compiler.

Official Patches

CodeIgniter FoundationGitHub Security Advisory GHSA-c9w5-rwh3-7pm9
CodeIgniter FoundationFix Commit f5e463b9a3e986389ce285963e51a7f1fab6559f

Fix Analysis (2)

Technical Appendix

CVSS Score
9.4/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H
EPSS Probability
0.38%
Top 70% most exploited

Affected Systems

CodeIgniter4 full-stack PHP framework deployments executing on PHP environments

Affected Versions Detail

Product
Affected Versions
Fixed Version
CodeIgniter4
CodeIgniter
>= 4.3.0, < 4.7.44.7.4
AttributeDetail
CWE IDCWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Attack VectorNetwork
CVSS v3.1 Score9.4 (Critical)
EPSS Score0.00377
EPSS Percentile30.46
Exploit MaturityProof of Concept / Analytical
CISA KEV StatusNo

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
CWE-89
Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

Known Exploits & Detection

GitHub Security Advisory TestsThe advisory lists clear unit tests reproducing the exact SQL compile outputs showing unescaped strings when where() matches the parameter structure.

Vulnerability Timeline

Initial vulnerability fix commit f5e463b9a3e986389ce285963e51a7f1fab6559f submitted to repository
2026-05-22
Hardening commit 953309e3d1335d449a27c1584805b35f50abea08 added for updateBatch()
2026-06-30
CodeIgniter version 4.7.4 published and Security Advisory GHSA-c9w5-rwh3-7pm9 disclosed
2026-07-31
EPSS Score calculated and published
2026-08-07

References & Sources

  • [1]CVE-2026-63221 Reference Record
  • [2]NVD CVE-2026-63221 Details
  • [3]CodeIgniter4 Security Advisory GHSA-c9w5-rwh3-7pm9
  • [4]CodeIgniter4 Release v4.7.4 Changelog

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 2 hours ago•CVE-2026-63222
7.5

CVE-2026-63222: Remote Code Execution via Path Traversal in CodeIgniter4 File Upload Handler

CVE-2026-63222 details a high-severity path traversal vulnerability in CodeIgniter4 versions prior to 4.7.4. The flaw lies within the `UploadedFile::move()` handler, which falls back to unsanitized, client-provided file names from the HTTP multipart request when a target name is not explicitly passed. An unauthenticated remote attacker can exploit this flaw to traverse arbitrary server directories, write malicious PHP payloads to the public-facing web root, and execute arbitrary code on the target system.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 3 hours ago•CVE-2026-63223
9.8

CVE-2026-63223: Unrestricted File Upload leading to Remote Code Execution in CodeIgniter4

A critical unrestricted file upload vulnerability (CWE-434) in CodeIgniter4 allows unauthenticated remote attackers to execute arbitrary code. By bypassing weak validation filters in the `is_image` and `mime_in` rules, an attacker can upload a malicious PHP payload disguised as a valid image file.

Amit Schendel
Amit Schendel
3 views•6 min read
•about 4 hours ago•CVE-2026-67422
7.5

CVE-2026-67422: Regular Expression Denial of Service in pymdown-extensions

A high-severity Regular Expression Denial of Service (ReDoS) vulnerability in pymdown-extensions versions prior to 11.0.1 affects the Caret, Tilde, BetterEm, and MagicLink inline processors. When parsing user-supplied Markdown content containing malicious sequences of formatting delimiters, the regular expression engine is forced into catastrophic backtracking, resulting in CPU exhaustion and application denial of service.

Alon Barad
Alon Barad
3 views•5 min read
•about 5 hours ago•CVE-2026-71847
8.7

CVE-2026-71847: Use-After-Free in Ruby JSON Gem ResumableParser

A technical analysis of the use-after-free (UAF) vulnerability in the Ruby JSON gem (CVE-2026-71847) that impacts versions 2.20.0 through 2.21.1. This vulnerability occurs when parsing incomplete stream data containing duplicate keys.

Alon Barad
Alon Barad
3 views•6 min read
•about 6 hours ago•CVE-2026-71848
5.3

CVE-2026-71848: Algorithmic Complexity Denial of Service in Hono languageDetector Middleware

An Algorithmic Complexity Denial of Service (DoS) vulnerability exists in the Hono web application framework within its languageDetector middleware. From version 4.12.0 to 4.12.33, the progressive language-tag truncation routine (normalizeLanguage) performs string operations with a quadratic time complexity O(N^2) relative to the number of hyphen-separated subtags in the user-supplied language tag. This allows an unauthenticated remote attacker to cause resource exhaustion and CPU spikes, resulting in a full denial of service of the single-threaded JavaScript runtime.

Alon Barad
Alon Barad
4 views•5 min read
•about 7 hours ago•CVE-2026-71849
3.7

CVE-2026-71849: Information Exposure via Hop-by-Hop Header Leakage in Hono Proxy Helper

A vulnerability in the Hono framework's Proxy Helper allows the exposure of connection-scoped, internal, or session-specific metadata to unauthorized actors. The proxy helper fails to remove header fields dynamically listed in the response's Connection header, violating RFC 9110 Section 7.6.1.

Amit Schendel
Amit Schendel
4 views•6 min read