ALL PLANS

SQL guardrails: every statement checked before it reaches your database

SQL guardrails are the blocking feature of Vericto's database guardrails: they evaluate every statement against your workspace rules before it runs and prevent the DELETE without WHERE, the DROP and the TRUNCATE nobody meant to run, whether the SQL comes from your application, a migration or an AI agent.

Sample output, as the docs describe it.

Deterministic SQL guardrails

Vericto does not guess. It parses each statement into its syntax tree (AST), with pg_query for Postgres and sqlparser-rs for MySQL, Oracle, SQL Server, Snowflake and SQLite, and evaluates your workspace's active rules on that tree. No ML and no thresholds: the same SQL with the same rules always gets the same verdict. The engine is open source (AGPL-3.0) and on GitHub.

What it blocks and what it flags

RiskRulesDefault
DELETE and UPDATE without WHERE, with an always-true WHERE (1=1, OR 1=1) or with LIMIT 0 on MySQL and SQLiteVERICTO-001, 002, 003, 030, 042, 090block
DROP TABLE, DROP DATABASE and DROP SCHEMAVERICTO-010, 012block
TRUNCATEVERICTO-011block
Risky DDL: DROP INDEX without IF EXISTS, DROP COLUMN, RENAME, DROP CONSTRAINT, ALTER COLUMN TYPE, DISABLE TRIGGER or ROW LEVEL SECURITY, and DROP TRIGGERVERICTO-013, 015–019block
SELECT without LIMIT and SELECT * without WHEREVERICTO-050, 051flag
Bulk loads: INSERT of more than 10,000 rows and COPY … FROM a file on the serverVERICTO-061flag
COPY … PROGRAM (a shell command on the server) and anonymous DO blocksVERICTO-080, 081block
GRANT and REVOKEVERICTO-082block
MERGE and CREATE TABLE AS SELECTVERICTO-083, 084block

The default action follows the severity: CRITICAL and HIGH block, MEDIUM lets the query through and raises an alert (flag), and LOW and INFORMATIONAL only record it (monitor). The workspace owner or an admin can change the action per severity or start in observe mode. From the Builder plan you can add your own rules in YAML.

DROP TRIGGER (VERICTO-019) and COPY … FROM a server file (VERICTO-061) are reported from engine version 3.9.0, which the TCP proxy includes from its version 4.9.0. The Vericto evaluator, which serves the API, the CLI and MCP, reports them once it adopts that engine version.

42 rules · 6 dialects · 8 incident families · 52 scenarios

The scenarios range from a DELETE without WHERE written by an agent to a COPY … TO PROGRAM injected through an MCP server. Each one has its rule, default action, dialects and origin in the rules reference, with a filter by family.

A DELETE hidden in a CTE, a tautology in a derived table or a UNION arm, a DROP stacked after a COMMIT, an INSERT … SELECT inside a SQLite trigger: the engine walks the syntax tree down to 50 levels and evaluates every statement of a multi-statement string. Anything deeper, or anything the parser cannot read, does not pass silently: it is recorded as a parse error, and blocked if you choose parse_error: block.

Measured latency, with its conditions

Measured on dedicated EC2 on October 31, 2026 (BENCH-2026-11, refresh for 4.21.0): vericto-proxy 4.21.0 (engine 4.6.0, 42 built-in rules, default policy) in enforce mode with full telemetry, limited to 0.5 vCPU (one Graviton3 core with a 50% CFS quota, as a Fargate task), TLS on both legs, on a c7g.2xlarge with PostgreSQL 17.11 and MySQL 8.4.13, and load from a c7g.xlarge in the same cluster placement group. Open loop at fixed rates, latency from the intended send time, 60 s warm-up and 300 s measured per cell, 3 interleaved repetitions, each paired with the direct path at the same rate in the same repetition; the headline curves were repeated on fresh hosts.

  • Added at p50 (proxy minus direct): PostgreSQL 0.08 ms from 967 to 4,834 statements/s (pgbench select-only, extended protocol; the direct path, 0.30 to 0.32 ms); MySQL 1.1 ms per sysbench oltp_read_only transaction of 16 statements and about 40 KB, about 0.07 ms per statement, from 36 to 250 transactions/s.
  • Added at p99: PostgreSQL 0.13 ms at 10% of the task's capacity, 0.28 ms at 30% and 0.60 ms at 50%; MySQL 1.33 ms per transaction at 10% and 1.54 to 2.01 ms from 30 to 70%. The tail grows with the load on the 0.5 vCPU quota (the CFS quota's waits, not the evaluation): size the task to run at about 50% of its CPU. A TCP-only hop (HAProxy) with the same CPU budget added 0.03 to 0.04 ms at p50 on PostgreSQL.
  • Statement size (staging context, not this run): what is added grows with size. On staging on October 16, 2026 (vericto-proxy 4.12.0, 0.25 vCPU), a 10-row INSERT added 0.58 ms at p50 on PostgreSQL; 100 rows, 1.05 ms, already above a millisecond; 500 rows, 3.07 ms; 1,000 rows, 5.54 ms. The EC2 size sweep is in the follow-up batch.
  • Rule evaluation alone, no network (staging, October 16, 2026): p99 of 100 µs or less for the OLTP statements (vericto-engine 3.9.0 on 0.25 vCPU ARM64).

It is a measurement under those conditions, not a guarantee: your network (here the proxy-to-database leg is on the same host), CPU size, statements and result sizes change the result. Observe mode, masked columns, 1 vCPU and large statements were not part of this run. Full method, charts and limitations: proxy latency benchmark.

What a verdict looks like

Three statements from a script, checked with check_sql. Each finding carries the line, the status, the rule, the severity and the suggested fix:

BLOCKED: 3 of 3 statements must not ship as written.
- line 1 BLOCKED VERICTO-001 (critical): DELETE FROM orders Fix: DELETE FROM orders WHERE id = $1
- line 2 BLOCKED VERICTO-010 (critical): DROP TABLE orders Fix: Use a versioned migration tool (Flyway, Prisma Migrate, Alembic, Rails migrations)
- line 3 BLOCKED VERICTO-080 (critical): COPY orders FROM PROGRAM 'curl -s https://example.com/x.csv' Fix: Use client-side \copy or COPY … TO STDOUT, never PROGRAM

The DROP TABLE comes back BLOCKED: check_sql is an agent asking right before it runs the SQL, so it blocks as at runtime. Through the CLI or in CI, the same statement comes back FLAGGED, because there a migration is reviewed by people.

The dashboard's Queries page with sample data: 39 blocked out of 1,263 queries in the last 24 hours, the hourly chart of allowed, blocked and flagged queries, and the list of statements with their rule, status, database and source: UPDATE users SET role = 'admin' blocked with VERICTO-030 through the MCP proxy, SELECT * FROM orders flagged with VERICTO-050, a read of customers with the email masked (VERICTO-085) and DROP TABLE invoices blocked with VERICTO-010.
The dashboard's Queries page, with sample data: the hourly chart and every statement with its rule, its status (blocked, flagged or allowed), the database and the source.

Where it is enforced

  • TCP proxy for Postgres and MySQL: it runs in your infrastructure, and a blocked query never reaches the database. The application gets its driver's native error, SQLSTATE 42501 on Postgres and ERROR 1142 on MySQL, with the rule.
  • Runtime API: your application sends each query before running it and runs it only if the response is 200. It also covers Oracle, SQL Server, Snowflake and SQLite.
  • CLI and CI: vericto check in pre-commit and in the pipeline, or the GitHub Action, which annotates the findings on the PR and fails the job on a block.
  • MCP: your coding agent calls check_sql while it writes the migration or the query. It is the same engine, so it works as a database guardrail for AI agents before a commit exists.
- uses: vericto/check-sql@v1
  with:
    api-key: ${{ secrets.VERICTO_API_KEY }}

Dialects: PostgreSQL, MySQL, Oracle, SQL Server, Snowflake and SQLite. The TCP proxy covers Postgres and MySQL; the Runtime API, the CLI and MCP cover all six.

At runtime and in MCP it blocks; in CI, migrations report

A versioned migration has every reason to contain DROP, ALTER and TRUNCATE. So in the CLI (vericto check), the Validation API and the dashboard dry-run, the schema and DDL rules (VERICTO-010 to 019) are capped at flag (schema_migration_cap): the pipeline reports the finding and does not fail, and people review the migration in the PR. Destructive DML, such as a DELETE without WHERE, and the security rules keep your workspace's action there. MCP check_sql, the Runtime API, the SDKs and the TCP proxy have no cap: every rule applies its full action, so an agent's DROP TABLE is blocked.

Limits

  • A statement that cannot be parsed is forwarded and recorded as PARSE_ERROR (fail-open) by default, so traffic is not cut. The owner or an admin can switch the workspace to fail-closed.
  • On MySQL, text that MySQL and the engine could read differently, because of its executable comments and string escapes, is always blocked (VERICTO-086). That rule cannot be disabled or lowered in severity.
  • Vericto reads the SQL, not your schema or your data: a tautology that depends on a column's values, such as WHERE id = 1 OR id > 0, is out of its scope.
  • It is defence in depth: your database's roles, permissions and backups are still needed.

The standard rules are on every plan, Free included. Custom YAML rules are available from the Builder plan.

Keep reading

Try it on your own SQL

The Free plan includes 500K queries a month and 1,000 CLI and MCP checks, with no credit card.

Start free