# SQL Injection Through Model Output — LLM Application Security

Source: https://www.geekswithgeeks.com/en/llm-security/o-sql

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

```python
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.

**Quiz:** Which design is safest for "ask questions about the database"?

- [x] 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.
