You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Which operating systems have you tested for this bug?
macOS
Which server did you use?
cli
Environment
Development
Database
SQLite3
What happened?
CodeIgniter\Database\SQLite3\Connection::execute() runs write-type queries through SQLite3::exec(), which executes multiple ;-separated statements, while read queries go through single-statement SQLite3::query():
Query bindings are the correct defense, and this is not a vulnerability in the framework itself. But when application code concatenates untrusted input into a write query (a common mistake), the SQLite3 driver turns a single mistaken statement into stacked-query execution: an attacker can append ; DROP TABLE ..., or ; ATTACH DATABASE '/path/x.db' AS v; ... to create a file at an arbitrary writable path and read/write other SQLite databases the process can reach. Most other drivers do not execute stacked statements from a single mistaken write, so the blast radius here is larger and specific to this driver.
Steps to Reproduce
$db->query("CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)");
$db->query("INSERT INTO t VALUES (1, 'a')");
$evil = "x'; CREATE TABLE marker(a); --";
// application code that forgot to bind the value:$db->query("UPDATE t SET name = '{$evil}' WHERE id = 1");
// table `marker` now exists — the appended statement ran.
Expected Output
A single write query executes a single statement. Statements appended after ; inside the string should not be executed, matching the behavior of the read path (SQLite3::query()) and of other drivers.
Anything else?
Proposal (for discussion): route write-query execution through a single-statement path — for example SQLite3::query() plus SQLite3::changes() for the affected-row count, or a prepared statement — instead of exec().
Backward compatibility: some applications may intentionally run multiple ;-separated statements in a single write (schema / migration / seed scripts). If a single-statement write path is undesirable, documenting the stacked-statement behavior of the SQLite3 driver would still help users reason about the risk.
User-supplied values should be passed through query bindings rather than concatenated into SQL. Multiple-statement execution is driver-dependent and can be used intentionally to run trusted SQL batches. Restricting execution to a single statement would not make concatenated user input safe, since SQL injection can also alter the original statement.
Let's see what others think, but I'm leaning toward keeping the current behavior.
for the thoughtful response.
You're right on all three points - single-statement execution wouldn't make concatenated input safe either way, and multi-statement writes are an intentional feature.
Bindings are the real fix. I'm convinced; happy for this to be closed. Thanks again.
Activity
carson-codeigniter4 commentedon Oct 23, 2026
michalsn commentedon Oct 23, 2026
User-supplied values should be passed through query bindings rather than concatenated into SQL. Multiple-statement execution is driver-dependent and can be used intentionally to run trusted SQL batches. Restricting execution to a single statement would not make concatenated user input safe, since SQL injection can also alter the original statement.
Let's see what others think, but I'm leaning toward keeping the current behavior.
secretj commentedon Oct 23, 2026
for the thoughtful response.
You're right on all three points - single-statement execution wouldn't make concatenated input safe either way, and multi-statement writes are an intentional feature.
Bindings are the real fix. I'm convinced; happy for this to be closed. Thanks again.