← Siddharth GaurResume

QueryPilot: natural language to SQL

Ask a database questions in plain English. An LLM writes the SQL, but nothing trusts it: the guarantee that a query can’t write sits at the database connection, not in parsing text an attacker controls.

Terminal output of query-injection-bench against QueryPilot v2: the default adapter lets several SQL-injection attacks succeed, the scoped adapter blocks them and the run passes the CI baseline.
query-injection-bench: default vs scoped adapter, gated in CI.

Problem

  • An LLM generating SQL against a real database is an injection surface. Filtering the SQL text means relying on the part an attacker controls.
  • Read-only is not the same as safe: an unscoped assistant will happily read your secrets table.

Approach

  • The real boundary is PRAGMA query_only plus a SQLite authorizer that denies non-read operations at prepare time. The other safety layers are early, friendly rejections, not the guarantee.
  • Each table’s DDL and sample rows are indexed as their own chunk, and each question retrieves only the top 3 for the prompt, rather than dumping the whole schema.
  • Every PR is scored against query-injection-bench, 129 adversarial SQL cases plus a false-positive set, and CI fails if the guard loses ground on the committed baseline.

What failed, and the tradeoffs

  • One attack survives scoping: column-level over-reach, which needs per-user authorization above this layer.
  • On the golden set with llama3.2 on CPU, exact match was 5.0%. That is a string comparison and a floor on correctness: most misses are the model aliasing aggregates, as the repo’s own prompt asks.
  • Execution success was 95.0%, but that only means the SQL passed the safety layers and ran. The one failure invented a column, and result-set comparison is not implemented.
  • Latency on that run was a mean of 59.2 s and a max of 328.2 s per question, on a CPU shared with another training process.

Result

  • Attack success rate 0.010 with a scoped table allow-list, against 0.089 with none; false-positive rate 0.000 in both.
  • With no LLM key, it serves the closest verified question through the full safety, retrieval and execution path against the real database.

Stack

  • Python
  • FastAPI
  • SQLite
  • ChromaDB
  • Postgres
  • Docker

Links

Next: ML Platform: feature store, drift monitor and fraud scoring →