{"id":"CVE-2026-63221","aliases":["EUVD-2026-51397","GHSA-c9w5-rwh3-7pm9","UBUNTU-CVE-2026-63221"],"status":"published","title":"CodeIgniter: SQL injection is possible via Query Builder deleteBatch() when used with where() conditions","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","severity":{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00612,"percentile":0.49601,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-89"],"published":"2026-07-31T04:03:34Z","modified":"2026-10-28T02:30:45Z","fixes":[{"ecosystem":"Packagist","package":"codeigniter4/framework","fixed_in":["4.7.4"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"codeigniter4/framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.3.0"},{"fixed":"4.7.4"}]}]},{"source":"osv","ecosystem":"Packagist","package":"codeigniter4/framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"4.3.0"},{"fixed":"4.7.4"}]}],"versions":["v4.3.0","v4.3.1","v4.3.2","v4.3.3","v4.3.4","v4.3.5","v4.3.6","v4.3.7","v4.3.8","v4.4.0","v4.4.1","v4.4.2","v4.4.3","v4.4.4","v4.4.5","v4.4.6","v4.4.7","v4.4.8","v4.5.0","v4.5.1","v4.5.2","v4.5.3","v4.5.4","v4.5.5","v4.5.6","v4.5.7","v4.5.8","v4.6.0","v4.6.1","v4.6.2","v4.6.3","v4.6.4","v4.6.5","v4.7.0","v4.7.1","v4.7.2","v4.7.3"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"php-codeigniter-framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.13+dfsg1-1","3.1.13+dfsg1-2","3.1.13+dfsg1-2ubuntu2","3.1.13+dfsg1-3"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"php-codeigniter-framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.13+dfsg1-8","3.1.13+dfsg1-9"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"php-codeigniter-framework","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["3.1.13+dfsg1-6","3.1.13+dfsg1-8"]}],"products":[{"vendor":"codeigniter4","product":"codeigniter4"}],"references":[{"url":"https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-c9w5-rwh3-7pm9","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/codeigniter4/CodeIgniter4/commit/f5e463b9a3e986389ce285963e51a7f1fab6559f","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.7.4","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-63221","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-c9w5-rwh3-7pm9"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63221.json","tags":["advisory"]},{"url":"https://github.com/codeigniter4/CodeIgniter4","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-63221","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-63221","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-63221","title":"CodeIgniter: SQL injection is possible via Query Builder deleteBatch() when used with where() conditions","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","status":"published","published":"2026-07-31T04:03:34.352Z","modified":"2026-07-31T13:52:40.376Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical","assessor":"cna"}],"cwes":["CWE-89"],"updated_at":"2026-11-02T14:19:55.914391Z"}],"euvd":[{"id":"EUVD-2026-51397","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","status":"published","published":"2026-07-31T04:03:34Z","modified":"2026-07-31T13:52:40Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T18:02:26.304051Z"}],"ghsa":[{"id":"GHSA-c9w5-rwh3-7pm9","title":"CodeIgniter: SQL injection in Query Builder deleteBatch() when used with where() conditions","description":"### Impact\nA SQL injection vulnerability exists in the Query Builder's `deleteBatch()` method. When `deleteBatch()` is used together with `where()` conditions, the bound values from the `WHERE` clause are substituted directly into the generated SQL **with their escape flag ignored**, so they are never escaped or quoted. If an application passes user-controlled input to `where()` before calling `deleteBatch()`, that input is interpreted as SQL rather than as a value, allowing SQL injection.\n\nThis affects only the `deleteBatch()` code path. Regular `delete()` operations escape `where()` binds correctly.\n\n### Patches\nUpgrade to v4.7.4 or later.\n\n### Workarounds\nIf you cannot upgrade immediately:\n\n- Strictly validate and cast values (e.g. numeric IDs) before using them in conditions - though this does not fully protect string conditions.\n- Do not pass user-controlled input to `where()` when using `deleteBatch()`.\n- For user-controlled conditions, use a normal `delete()` with Query Builder binds instead of `deleteBatch(`).\n- Where possible, express required matching values through the batch data and `onConstraint()` rather than as separate user-controlled `where()` clauses.","status":"published","published":"2026-08-07T18:22:59Z","modified":"2026-08-07T18:23:00Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical"}],"cwes":["CWE-89"],"updated_at":"2026-11-02T14:40:58.888637Z"}],"nvd":[{"id":"CVE-2026-63221","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","status":"published","published":"2026-07-31T06:16:31.603Z","modified":"2026-09-08T20:51:43.49Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-89"],"updated_at":"2026-11-02T14:12:33.955581Z"}],"osv":[{"id":"CVE-2026-63221","title":"CodeIgniter: SQL injection is possible via Query Builder deleteBatch() when used with where() conditions","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","status":"published","published":"2026-07-31T04:03:34.352Z","modified":"2026-10-28T02:30:45.793577807Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical"}],"cwes":["CWE-89"],"updated_at":"2026-11-02T15:45:13.306117Z"},{"id":"GHSA-c9w5-rwh3-7pm9","title":"CodeIgniter: SQL injection in Query Builder deleteBatch() when used with where() conditions","description":"### Impact\nA SQL injection vulnerability exists in the Query Builder's `deleteBatch()` method. When `deleteBatch()` is used together with `where()` conditions, the bound values from the `WHERE` clause are substituted directly into the generated SQL **with their escape flag ignored**, so they are never escaped or quoted. If an application passes user-controlled input to `where()` before calling `deleteBatch()`, that input is interpreted as SQL rather than as a value, allowing SQL injection.\n\nThis affects only the `deleteBatch()` code path. Regular `delete()` operations escape `where()` binds correctly.\n\n### Patches\nUpgrade to v4.7.4 or later.\n\n### Workarounds\nIf you cannot upgrade immediately:\n\n- Strictly validate and cast values (e.g. numeric IDs) before using them in conditions - though this does not fully protect string conditions.\n- Do not pass user-controlled input to `where()` when using `deleteBatch()`.\n- For user-controlled conditions, use a normal `delete()` with Query Builder binds instead of `deleteBatch(`).\n- Where possible, express required matching values through the batch data and `onConstraint()` rather than as separate user-controlled `where()` clauses.","status":"published","published":"2026-08-07T18:22:59Z","modified":"2026-08-07T18:31:29.631096337Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical"}],"cwes":["CWE-89"],"updated_at":"2026-11-02T15:46:44.927642Z"},{"id":"UBUNTU-CVE-2026-63221","description":"CodeIgniter is a PHP full-stack web framework. From 4.3.0 through 4.7.3, Query Builder deleteBatch() substitutes bound values from where() conditions into generated SQL while ignoring their escape flags, allowing user-controlled condition values to be interpreted as SQL. This affects only the deleteBatch() code path. Regular delete() operations escape where() binds correctly. This issue is fixed in version 4.7.4.","status":"published","published":"2026-07-31T06:16:00Z","modified":"2026-10-17T12:59:15.418874386Z","cvss":[{"version":"3.1","score":9.4,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T16:56:43.630667Z"}]}}
