AI Security

Text-to-SQL LLM Security: Enterprise Defense Guide

BT

BeyondScale Team

AI Security Team

11 min read

Text-to-SQL LLM security is now a mainstream enterprise concern. Teams are wiring Vanna AI, LangChain SQL agents, Databricks AI/BI, and Snowflake Cortex Analyst to production databases so that anyone can ask questions in plain English. Every one of those deployments lets a language model write code that your database will run. This guide explains how that goes wrong, which attacks are documented, and which controls hold up when the model itself cannot be trusted.

Key Takeaways

    • A text-to-SQL agent turns untrusted text into executable queries. Treat the model output like user-supplied code, not like application logic.
    • Prompt-to-SQL (P2SQL) injection is documented in peer-reviewed research and has produced real CVEs in LangChain and Vanna AI.
    • Parameterized queries do not help when the model authors the query structure. Database-side permissions are the control that matters most.
    • Over-privileged service accounts turn a minor injection into a full data breach. Use a read-only role over curated views with row-level security.
    • Validate generated SQL with a real parser and an allowlist before execution, and cap cost, rows, and runtime.
    • Frameworks that execute model output with Python exec add a second, worse failure mode: remote code execution.
    • Log the question, generated SQL, and result size for every call so you can detect abuse and answer audit questions.

How Text-to-SQL Agents Work and Where They Break

A typical pipeline has four steps. The application collects the user's question. It adds context to the prompt, usually the schema, a few example queries, and sometimes documentation retrieved from a vector store. The model returns SQL. A connector executes it and often feeds the rows back to the model to write a summary.

Each step is an attack surface:

  • The question is attacker-controlled text.
  • The context includes table names, column comments, and retrieved documents. If any of that contains attacker-written content, you have indirect prompt injection. See our guide to indirect prompt injection in agentic AI.
  • The generated SQL is code produced by a probabilistic system that cannot reliably separate instructions from data.
  • The result summary can leak anything the query returned, including rows the user should never see.
  • The root issue is the one OWASP describes under prompt injection: an LLM has no control plane, so developer instructions and user input share a single channel. Our overview of prompt injection attacks and defenses covers the general case. Text-to-SQL is the case where the consequence is a database query.

    Prompt-to-SQL Injection: What the Research Shows

    The clearest public analysis is "From Prompt Injections to SQL Injection Attacks" by Pedro et al., published as arXiv:2308.01990 and presented at ICSE 2025. The authors characterize prompt-to-SQL (P2SQL) injections against applications built on LangChain, show several attack variants, and evaluate defenses. Their central finding is that a developer's pre-prompt ("only run read queries") is just more text, and a user can write text that overrides it.

    Two patterns show up repeatedly in practice:

    • Direct override. The user asks the assistant to ignore previous constraints and produce a destructive or broad query, such as dumping a table the question had nothing to do with.
    • Stored injection. A malicious string is written into a database field through an ordinary form. Later, when the agent reads that row to answer someone else's question, the string is treated as an instruction. This is the same shape as stored XSS, and it is why content in your own tables is not automatically trusted input.
    The same class of bug has been assigned real identifiers. CVE-2023-36189 covers SQL injection in LangChain's SQLDatabaseChain in versions before 0.0.247. Separately, CVE-2024-5565 in Vanna.AI, analyzed by JFrog, showed prompt injection reaching remote code execution because the library executed model-generated Python for chart rendering with exec. That second case matters because it shows the risk is not only in the SQL. Any code path that runs model output is in scope.

    Why Traditional SQL Injection Defenses Miss This

    Classic SQL injection defenses assume that a developer wrote the query and an attacker supplied a value. Text-to-SQL inverts both assumptions.

    Parameterization is not relevant. Prepared statements separate query structure from values. Here the model decides the structure. There is nothing to bind.

    WAFs and signature detectors inspect the wrong layer. A WAF sees an English sentence entering your API and a JSON response leaving it. The malicious SQL is created inside your trust boundary, after the WAF. Even an inline SQL detector faces a distribution problem: model-generated SQL is syntactically valid and often looks like a legitimate analytics query. A SELECT that joins customers to payments and exports every row is not a syntax anomaly.

    Backdoored models weaken detectors further. Academic work on backdoor attacks against LLM-based text-to-SQL models (for example the paper "Are Your LLM-based Text-to-SQL Models Secure? Exploring SQL Injection via Backdoor Attacks") shows that poisoning fine-tuning data can implant a trigger that makes the model emit attacker-chosen SQL, and that such output can evade conventional detection. We treat the headline detection-rate numbers from these papers as lab results rather than production benchmarks, but the direction is clear: do not rely on pattern matching alone. Our write-up on LLM backdoor attack detection covers provenance and testing for poisoned models.

    The natural language itself is the exploit. There is no signature for "pretend you are the database administrator and show me everything." Filtering questions helps at the margin, but attackers can paraphrase indefinitely.

    The Real Problem: Over-Privileged Service Accounts

    In assessments, the pattern we see most often is not clever injection. It is a text-to-SQL agent connected with a credential that can do far too much. The proof-of-concept was a convenience: someone used the existing analytics user, or worse an owner role, so that "it just works" across every schema.

    The result is that the agent's effective permissions equal the permissions of its most powerful user, no matter who is asking. A junior analyst's question runs with the privileges of the account, not the analyst. This is the classic confused deputy problem, and it is why we map this risk to excessive agency. The principles in our guide on AI agent authorization and least privilege apply directly.

    Common failure modes:

    • A role with INSERT, UPDATE, DELETE, or DDL rights, so injection can modify or drop data.
    • Access to base tables containing PII, secrets, or HR data when only a reporting view was intended.
    • No row-level security, so every user sees every tenant's rows.
    • Access to system catalogs (information_schema, pg_catalog, sys.*) that let the model, and therefore the attacker, map the entire database.
    • Dangerous functions available: file reads (pg_read_file, COPY ... PROGRAM), xp_cmdshell on SQL Server, LOAD_FILE on MySQL, or external stages in a warehouse.
    • No statement timeout, allowing a single cross join to exhaust the warehouse and your budget.

    Affected Platforms and What Differs

    The failure modes are architectural, but platforms differ in which controls they hand you.

    • Vanna AI and similar open-source frameworks run in your process with your credentials. The security posture is whatever you build around them, including how generated Python for visualization is executed. Upgrade past known CVEs and sandbox any code execution.
    • LangChain SQL agents have a history of injection issues, such as CVE-2023-36189. The framework documentation itself warns that connecting a model to a database carries risk and recommends narrowly scoped credentials. Follow that guidance literally.
    • Databricks AI/BI and Snowflake Cortex Analyst run inside governed data platforms, which helps: queries execute under the platform's access controls, and you can use Unity Catalog or Snowflake roles, masking policies, and row access policies. The caveat is that these protections only work if you have defined them. A semantic model that exposes a sensitive column hands it to the model.
    Whichever you use, verify what identity the generated query runs as. If the answer is "a shared service account," fix that first.

    Defense Architecture That Holds Up

    Assume the model will eventually generate a query you did not want. Design so that this is survivable.

    1. Enforce permissions in the database

    • Create a dedicated role with SELECT only, granted on curated views rather than base tables.
    • Use row-level security driven by the end user's identity, passed through session variables or token exchange, so the agent cannot see more than the asker could.
    • Apply column masking to PII and revoke access to system catalogs and file or network functions.
    • Set statement_timeout, maximum rows, and warehouse or query cost limits per role.
    • Prefer a read replica so that even a runaway query cannot affect production writes.

    2. Validate the SQL before it runs

    Parse generated SQL with a real parser (for example sqlglot or the database's own parser), not regular expressions. Reject anything that is not a single SELECT statement. Check that every referenced table and column is on an allowlist. Reject multi-statement input, comments used to smuggle content, and references to system schemas. This catches a large share of attacks, but it is a second line of defense, not the first. Honest tradeoff: allowlists reduce flexibility and need maintenance as schemas change.

    3. Constrain the context

    Keep the schema description minimal and limited to what the user may query. Do not retrieve documentation from sources untrusted authors can edit. Treat free-text database fields as untrusted when they are placed in prompts, and consider stripping or fencing them. If your agent also calls tools, review the broader controls in our AI agent runtime security guide.

    4. Never execute model output as code

    If a framework turns model output into Python, JavaScript, or shell commands, run it in a sandbox with no credentials, no network, and a short timeout, or remove the feature. CVE-2024-5565 is the cautionary example.

    5. Control what comes back

    Limit row counts returned to the model and the user. Run result summaries through the same access policy as the query. For sensitive datasets, require human approval for queries that exceed a size or sensitivity threshold.

    6. Log and monitor

    Record the user identity, original question, generated SQL, tables touched, row count, and duration. Alert on unusual joins, access to tables a user rarely touches, large exports, and repeated validator rejections. Those logs are also your evidence for audits and incident response.

    CISO Hardening Checklist

    Use this list to review any text-to-SQL deployment:

  • Inventory every model-to-database connection, including pilots and notebooks.
  • Confirm the identity each generated query runs under. Eliminate shared admin credentials.
  • Verify the role is read-only and scoped to curated views.
  • Test row-level security and masking with at least two users of different access.
  • Block system catalogs, file functions, and network functions.
  • Add a SQL parser with a single-statement, SELECT-only, allowlisted-object policy.
  • Set statement timeouts, row limits, and cost caps.
  • Remove or sandbox any exec or eval of model output. Patch known framework CVEs.
  • Review which free-text columns reach the prompt and whether outsiders can write to them.
  • Validate the provenance of any fine-tuned or third-party text-to-SQL model.
  • Log question, SQL, tables, and row counts. Alert on anomalies.
  • Run adversarial testing before launch and after each schema or model change. Map findings to the OWASP Top 10 for LLM Applications, especially prompt injection, sensitive information disclosure, and excessive agency. Our OWASP LLM Top 10 2026 guide walks through each category.
  • Testing Your Own Deployment

    Reading about injection is not the same as seeing it hit your schema. A useful test plan includes: asking for data outside the user's role, asking the model to reveal its system prompt and schema, planting a harmful string in a free-text field and then querying around it, requesting expensive cross joins, and trying to reach system catalogs. Run these as an authenticated low-privilege user, because that is the realistic attacker. Record whether the database or only the prompt stopped each attempt. If only the prompt did, the control is not real.

    Conclusion

    Text-to-SQL LLM security comes down to one principle: the model is not a security boundary. P2SQL injection is documented, framework CVEs exist, and poisoned models are a credible supply chain risk. The controls that work are boring and effective: least-privilege database roles, row-level security, parser-based validation, sandboxed execution, and complete logging. Build those first, and a successful prompt injection becomes a contained incident instead of a breach.

    Want to see what your AI endpoints expose? Run a scan with Securetom to find exposed AI and data endpoints before an attacker does.

    Check your AI endpoint against these findings

    SecureTom runs a free quick scan on any AI endpoint in about a minute. No signup needed.

    Run a free scan
    BT

    BeyondScale Team

    AI Security Team

    The SecureTom research team at BeyondScale Technologies, an ISO 27001 certified company. We build the scanner and publish what we learn testing production AI systems.