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.