Text-to-SQL security is a distinct problem from classic parameterized-query hygiene. With an LLM in the loop, the query itself is generated from untrusted natural language, so a prompt injection can steer the model into producing SQL that is syntactically valid but unauthorized, destructive, or data-leaking.
Parameterization protects individual literals, but the LLM writes the whole statement — table names, joins, and clauses included. The real guardrail is a validation layer that inspects the generated SQL as structure, not text.
In classic SQL injection an attacker controls one parameter inside a query a developer wrote. With an LLM, the attacker only needs to get text into the model’s context — a user message, a support ticket, a row the agent read earlier — and the model writes the malicious query itself. That chain has three steps:
You cannot reliably break step 1 or step 2, because both are probabilistic. Step 3 is where enforcement is deterministic: the query is a concrete artifact you can parse and reject.
A blind attacker who cannot see query results can still extract data one bit at a time. The injected instruction steers the model into a query like SELECT CASE WHEN (condition) THEN pg_sleep(5) END: if the response is slow, the condition was true. Repeat that across enough conditions and the attacker reconstructs values without a single row being returned.
A read-only role does not stop this, because sleep functions are readable by default. QueryShield rejects pg_sleep, MySQL’s SLEEP and BENCHMARK, and the other deny-listed functions anywhere in the AST — including inside subqueries and CTEs — so the timing channel never opens.
QueryShield applies all of these as a proxy in front of your database, and audit-logs every decision. Because the agent only ever talks to the proxy, it never sees connection strings or credentials to abuse in the first place.
A secure SQL proxy for AI agents: natural language in, SELECT-only validated SQL out, per-agent row-level security, and an append-only audit log. Your agents never see connection strings.