Skip to content
Lyrra
← All articles

Data · 2 min read · 2026-09-24

Natural language to SQL without leaking your data: guardrails that matter

In short:Why asking a model to 'only write SELECT' is not a security control, and what to layer on top.

Letting people ask their database questions in plain English is appealing, and dangerous if done carelessly. A language model can be persuaded, confused or simply wrong. So the safety of the system cannot depend on the model behaving. Here are the layers we use in our own prototype, and why each one exists.

Layer 1: tell the model the rules

The prompt describes the allowed schema and the constraints: one SELECT statement, only allowed tables and columns, always include a LIMIT, and refuse anything else. It also helps to show the model only an allow-listed slice of the schema, so it cannot even name tables it should not see. This layer is useful and it is the weakest one. Never rely on it alone.

Layer 2: validate the SQL itself

Regular expressions are easy to bypass with comments, whitespace or encoding tricks. Parse the SQL into a syntax tree instead, and reject on structure: more than one statement, any mutating node anywhere in the tree, row-locking clauses, bare SELECT *, and any table or column outside the allow-list.

The 'anywhere in the tree' part matters. This query parses as a SELECT at the top level, yet contains a delete inside a common table expression:

WITH x AS (DELETE FROM customers RETURNING *)
SELECT * FROM x;

A check that only inspects the first keyword would let it through. Walking the whole tree catches it.

Layer 3: let the database refuse

Run the query as a database role that has SELECT-only permission on exactly the tables you exposed, with a statement timeout and no access to your audit log. Now even if the first two layers were bypassed, Postgres itself refuses to write. This is what turns a set of app-level checks into real defence in depth.

Small controls that add up

Test the guardrails, not just the happy path

In our prototype we probe each layer separately, including sending hostile SQL directly to the read-only connection to prove it is a real backstop and not just redundant. A guardrail you have not attacked is a guess.

If you are considering natural-language access to your own data, this is the kind of design we can review with you.

Free for now

Want a second pair of eyes on your plan?

Our AI opportunity audit is free for now: three ranked opportunities and a first step, in 2 business days.