FutrixData logo FutrixData
SQL guardrails

SQL Guardrails for AI Agents — Block Destructive Queries Before They Run

SQL guardrails for AI agents intercept dangerous statements (DROP, TRUNCATE, mass DELETE/UPDATE without WHERE, full-table scans, large bulk data fetches) before they reach your MySQL, PostgreSQL, or Cloudflare D1. FutrixData combines static rule matching with pre-execution EXPLAIN probes — so the same SELECT can be low risk on an indexed lookup and medium risk when the plan reveals a wide scan (e.g., 100k rows).

What "SQL guardrails" mean in an AI context

Database permissions answer "who can connect, who can read or write." Agents introduce a finer-grained problem: under one connection, different statements carry vastly different risk. SELECT * FROM orders WHERE id = 1001 is a point lookup; SELECT * FROM orders is a customer-data dump. Guardrails are the middle layer that distinguishes them.

Four risk categories

Two-layer evaluation: static rules + pre-execution EXPLAIN

Static rules catch the obvious (no WHERE, target table is audit_logs, etc.). The probe catches what a parser cannot: whether the query actually uses an index. FutrixData escalates risk when:

The probe only escalates risk; it never downgrades an operation already classified as high risk.

Built-in MySQL / PostgreSQL / D1 rules

StatementDefault action
SELECT, SHOW, DESCRIBE, EXPLAINallow
INSERT, REPLACE, UPDATE … WHERE, DELETE … WHEREwarn
UPDATE / DELETE without WHEREblock
CREATE, ALTERwarn
DROP, TRUNCATE, GRANT, REVOKEblock

User rules override built-ins by virtue of more precise scope and higher priority. For example: warn on UPDATE by default, but forbid any DELETE on orders in production.

Trust modes

Per-source trust modes decide what programmatic entry points (MCP, Skill, HTTP, CLI) can execute automatically.

ModeBehavior
ApprovalEvery execution requires human confirmation.
CautiousDefault. Only low-risk statements execute automatically.
TrustedLow- and medium-risk auto; high risk still requires confirmation.
DangerEverything auto-executes, including operations that would normally be blocked. Recommended only for disposable test data.

How approval works

When an agent hits a require_approval result, the proxy returns a structured response describing the matched rule and the parsed statement. The caller must reissue the request with approve: true. Approval is verified at the entry layer — agents can't simply pass approve: true into an arbitrary call to bypass interception.

Examples

Destructive query intercepted
// Agent attempts:
DELETE FROM users;

// FutrixData response:
{
  "ok": false,
  "risk": "block",
  "rule": "sql.delete_without_where",
  "reason": "DELETE without WHERE clause on table users",
  "data_source": "prod-postgres",
  "audit_id": "audit_01HQ7M..."
}
Reissue with explicit approval
// Caller reissues:
{
  "statement": "DELETE FROM users WHERE last_login < now() - interval '5 years'",
  "approve": true,
  "approval_reason": "scheduled GDPR purge, ticket OPS-2189"
}

Frequently asked questions

What does FutrixData block by default on SQL data sources?

DROP, TRUNCATE, GRANT, REVOKE, and UPDATE/DELETE without WHERE. Everything else lands at allow (reads) or warn (writes / DDL), with the trust mode deciding whether warns require approval.

Will I get false positives on legitimate queries?

The static rules are deliberately narrow — destructive ops and missing-WHERE patterns. The pre-execution EXPLAIN probe is the finer-grained layer; thresholds (max scan rows, max joins) are configurable per source, and small tables where the planner naturally chooses Seq Scan can be exempted by raising the full-scan row threshold.

Can I override a block?

Yes — for warn / require_approval, the caller resubmits with approve: true and a reason that lands in the audit log. Hard block rules (e.g., DROP in production) require a configuration change, not a per-call override; that's by design.

Does this work with raw SQL or only ORMs?

Raw SQL. FutrixData parses MySQL, PostgreSQL, and D1 syntax directly to extract command type, target table, WHERE presence, joins, and subqueries. ORMs that emit raw SQL are covered transparently.

How does MySQL handling differ from PostgreSQL?

The static rule set is the same. Probes differ: MySQL inspects full table scans, temporary tables, filesort, dependent subqueries, and join row estimates. PostgreSQL inspects sequential scans, join counts, subplans, and large result-set sorts. D1 inspects SCAN vs SEARCH and validates base-table scans after view expansion.

Does pre-execution EXPLAIN add latency?

Yes — typically one extra round-trip to the database before the real query runs. For point lookups it's milliseconds; for queries that fail the EXPLAIN check, the latency saved by not running them dwarfs the probe cost.

Try FutrixData on your own database

Free desktop app on macOS, Windows, and Linux. Self-hosted Enterprise Edition for production deployments.