Lesson 10 / 28
SQL Injection Through Model Output
See an injected value leak every row, and the parameterised fix.
Natural language to SQL needs extra care
A common feature is "chat with your database": the model turns a question into SQL. If the app executes whatever SQL the model writes, then a user (or a document the model reads) can make it produce DROP TABLE, a query on a table the user must not see, or an expensive query that stalls the database. Safer designs: let the model fill parameters of fixed, pre-written queries instead of writing SQL; if free-form SQL is unavoidable, connect with a read-only database account limited to specific views, add row-level security, parse and allow-list statement types (SELECT only), set timeouts and row limits, and never run it with an admin account. For values the model supplies, always use parameters, as the example shows: the same malicious value returns every row when concatenated into the query, and none when passed as a parameter.
Concatenation versus parameters, run
I ran this with plain Python 3 (standard library only). All attacks here are harmless demonstrations on local data, using no real systems. The "model output" asha' OR '1'='1 changes the meaning of the concatenated query so it returns all three customers. As a bound parameter the same text is only a value, matches no customer name and returns nothing.
import sqlite3
db = sqlite3.connect(":memory:")
db.executescript("""
create table orders (id integer, customer text, total integer);
insert into orders values (1, 'asha', 500), (2, 'ravi', 900), (3, 'meera', 1200);
""")
model_output = "asha' OR '1'='1" # text a model produced from a user's message (attacker-influenced)
unsafe = f"select id, customer from orders where customer = '{model_output}'"
print("UNSAFE rows:", db.execute(unsafe).fetchall())
print("SAFE rows:", db.execute("select id, customer from orders where customer = ?", (model_output,)).fetchall())
Output:
UNSAFE rows: [(1, 'asha'), (2, 'ravi'), (3, 'meera')] SAFE rows: []
Use read-only database accounts
Even if a bad query slips through, a read-only account on specific views limits the damage.
Quick check: Which design is safest for "ask questions about the database"?
- Model fills parameters of fixed queries, or runs read-only SQL with strict limits
- Run any SQL the model writes as admin
- Disable authentication
- Store passwords in the prompt
Answer
Model fills parameters of fixed queries, or runs read-only SQL with strict limits — Constrain the model to parameters and least-privilege access.