30 rules. None uses ML.

All Vericto standard rules and how to configure them.

How rules work

When a query reaches the Vericto proxy, the parser builds the complete AST (Abstract Syntax Tree) of the query. The engine traverses the tree in depth searching for nodes that violate the conditions defined in each active rule.

The process is always the same:

  1. The SQL query reaches the proxy as plain text
  2. The engine selects the right parser for the dialect (pg_query for Postgres, sqlparser-rs for MySQL, Oracle and SQL Server). PostgreSQL and MySQL can be evaluated by the TCP proxy; Oracle and SQL Server, by the HTTP API.
  3. The complete AST is built in memory
  4. The engine evaluates each active rule against the tree
  5. If any rule is violated, the query is blocked before reaching the database

Each rule defines exactly five properties:

  • Code: unique identifier in the form VERICTO-XXX or CUSTOM-XXX
  • AST condition: the node and property evaluated (e.g. DeleteStmt > WhereClause = NULL)
  • Dialect(s): one or more SQL dialects the rule applies to
  • Severity: one of the 5 CVSS levels — CRITICAL, HIGH, MEDIUM, LOW or INFORMATIONAL
  • Suggested safe query: the corrected version of the query shown in the block log

AST parsing adds on average less than 0.4ms to the response time. The total proxy p99 (parsing + rule evaluation + network overhead) is under 2ms.

Severity levels

Vericto uses the 5-level CVSS taxonomy. The default action can be customised per workspace with an EnforcementPolicy.

Severity Default action Behavior Alerts
CRITICAL BLOCK Immediate block of the query. SQLSTATE 42501 to the client. Real-time alert via webhook and dashboard
HIGH BLOCK Query blocked, fully recorded in the audit trail. Real-time alert
MEDIUM FLAG The query is forwarded upstream. Logged and alerted on, but not blocked. Alert (FLAG) in dashboard and webhook
LOW MONITOR The query is forwarded. Recorded in telemetry only, no alert. Telemetry / audit trail only
INFORMATIONAL MONITOR The query is forwarded. Informational logging, no action. Metrics only

On every plan, the workspace owner and admins can customize the EnforcementPolicy (change the action per severity or turn on observe mode). This is useful during adoption to observe traffic before enabling blocks.

CRITICAL rules

CRITICAL rules detect operations that can cause irreversible loss of massive amounts of data. They are active across all supported dialects unless otherwise indicated.

Code Name AST Condition Dialects Suggested safe query
VERICTO-001 DELETE without WHERE DeleteStmt > WhereClause = NULL All DELETE FROM {tabla} WHERE id = $1
VERICTO-003 DELETE with always-true WHERE DeleteStmt > WhereClause = ALWAYS_TRUE (1=1, true) All DELETE FROM {tabla} WHERE id = $1
VERICTO-010 DROP TABLE / DROP DATABASE DropStmt (excludes DROP INDEX) All Use versioned migrations (Flyway, Prisma Migrate, Alembic)
VERICTO-011 TRUNCATE TABLE TruncateStmt (nodo presente) All DELETE FROM {tabla} WHERE created_at < NOW() - INTERVAL '90 days'
VERICTO-012 DROP SCHEMA DropStmt > ObjectType = SCHEMA All Use versioned migrations
VERICTO-030 UPDATE without WHERE (main tables) UpdateStmt > WhereClause != Present All UPDATE {tabla} SET {col} = $1 WHERE id = $2
VERICTO-042 UPDATE without WHERE clause UpdateStmt > WhereClause = NULL (includes trivial WHERE) All UPDATE {tabla} SET {col} = $1 WHERE id = $2
VERICTO-080 COPY … TO/FROM PROGRAM CopyStmt > program = true Postgres Use COPY … TO/FROM STDIN or controlled file paths; never run shell commands from SQL
VERICTO-081 DO anonymous code block DoStmt (DO $$ … $$) Postgres Move the logic to a reviewed function/migration instead of an anonymous block opaque to the parser
VERICTO-086 SQL text that MySQL and the engine would read differently Text that cannot be resolved with certainty to a single statement because of how MySQL reads its comments and string escapes MySQL Always enforced: it cannot be disabled or downgraded. Send SQL without ambiguous comments or escapes

HIGH rules

HIGH rules detect high-risk operations that can cause partial data loss or irreversible structural changes.

Code Name AST Condition Dialects Suggested safe query
VERICTO-002 DELETE with LIMIT 0 DeleteStmt > LimitCount = 0 MySQL DELETE FROM {tabla} WHERE id = $1 LIMIT 1
VERICTO-013 DROP INDEX without IF EXISTS DropStmt > ObjectType = INDEX & IF_EXISTS = false All DROP INDEX IF EXISTS {index_name}
VERICTO-015 ALTER TABLE DROP COLUMN AlterTableStmt > AlterTableCmd.subtype = DROP_COLUMN All Use a soft delete with a deleted_at column, or a versioned migration
VERICTO-016 ALTER TABLE RENAME AlterTableStmt > Rename All Use a migration tool and update all references first
VERICTO-017 ALTER TABLE DROP CONSTRAINT AlterTableStmt > DropConstraint (FK/PK/CHECK, DROP PRIMARY KEY) All Drop the constraint only in a reviewed migration, after confirming no data or code depends on it
VERICTO-018 ALTER TABLE ALTER COLUMN TYPE AlterTableStmt > AlterColumnType All Perform the type change in a phased migration (new column + backfill) to avoid a blocking rewrite or lossy cast
VERICTO-019 ALTER TABLE DISABLE TRIGGER / RLS AlterTableStmt > DisableTrigger | DisableRowSecurity All Do not disable triggers or Row Level Security in production; if unavoidable, do it in a controlled window and re-enable them immediately
VERICTO-031 UPDATE without WHERE nested in CTE WithClause > UpdateStmt > WhereClause = NULL Postgres Add a WHERE with a specific predicate to the UPDATE inside the CTE
VERICTO-033 DELETE without WHERE in subquery/CTE WithClause/SubLink > DeleteStmt > WhereClause = NULL All Rewrite as DELETE with explicit JOIN and WHERE
VERICTO-040 INSERT INTO … SELECT without filter InsertStmt > source = SelectStmt All INSERT INTO {tabla} SELECT ... WHERE <condición> LIMIT N
VERICTO-070 Use of SLEEP() or PG_SLEEP() FunctionCall > name = sleep|pg_sleep All Remove the SLEEP call from the pipeline
VERICTO-082 GRANT / REVOKE GrantStmt (GRANT or REVOKE) All Manage privileges through reviewed permission migrations, not from application queries
VERICTO-083 MERGE MergeStmt All Constrain the MERGE with specific conditions; it can mass-mutate like an UPDATE/DELETE with no effective WHERE
VERICTO-084 CREATE TABLE AS SELECT CreateTableAsStmt / SELECT … INTO All Add a WHERE/LIMIT to the source to avoid duplicating an entire table
VERICTO-085 Read of a sensitive column A projection derived from a tagged column (SELECT, RETURNING, COPY … TO) All Decided by each database's sensitive columns: list the columns instead of SELECT * and do not project the tagged ones

MEDIUM rules

MEDIUM rules detect query patterns that may indicate an AI agent operating without adequate context, or that could degrade database performance.

Code Name AST Condition Dialects Suggested safe query
VERICTO-050 SELECT without LIMIT SelectStmt > LimitCount = NULL All SELECT ... WHERE <condición> LIMIT 1000
VERICTO-051 SELECT * without WHERE SelectStmt > TargetEntry = STAR & WhereClause = NULL All SELECT col1, col2 FROM ... WHERE <condición>
VERICTO-060 INSERT without explicit columns InsertStmt > Cols = NULL All INSERT INTO {tabla} (col1, col2) VALUES ($1, $2)
VERICTO-061 INSERT batch with more than 10k rows InsertStmt > ValuesList count > 10000 All Split into batches of ≤1,000 rows with multiple INSERT or COPY

SQL Injection rules

Deterministic detection of SQL injection patterns in LLM-generated queries. Unlike traditional WAFs based on text patterns, Vericto analyzes the AST, making detection immune to obfuscations that preserve semantics.

Code Name AST Condition Dialects Why it avoids false positives
VERICTO-090 OR tautology in WHERE WhereClause > BoolExpr(OR) > always_true_branch All An LLM generating legitimate queries never has a reason to include OR 1=1. They only exist in authentication-bypass attempts.

VERICTO-090 coverage: applies to WHERE clauses in SELECT, DELETE, and UPDATE. Detects patterns like OR 1=1, OR 'a'='a', OR true, and nested tautologies like AND (condition OR 1=1).

Snowflake rules

Seven rules for Snowflake (vericto-engine 4.0.0). They read only what the Snowflake parser records, so they never fire on another dialect. Snowflake has no TCP proxy: these rules apply in the HTTP API, the CLI in CI/CD and MCP.

Code Name AST Condition Dialects Suggested safe query
VERICTO-091 Stage unload or file transfer COPY INTO @stage | 's3://…' | 'azure://…' | 'gcs://…', GET, PUT Snowflake Load from the stage (COPY INTO table FROM @stage); data unloads go through a reviewed process outside the application
VERICTO-092 External stage or integration CREATE|ALTER STAGE … URL = | CREDENTIALS, CREATE STORAGE | EXTERNAL ACCESS | API INTEGRATION, CREATE EXTERNAL FUNCTION Snowflake Use an internal stage; integrations and external stages are created in reviewed migrations
VERICTO-093 Share to another account GRANT … TO SHARE, CREATE SHARE, ALTER SHARE … ADD | SET ACCOUNTS, CREATE LISTING Snowflake Sharing data is an account decision: make it outside application SQL
VERICTO-094 Recovery reduced DATA_RETENTION_TIME_IN_DAYS = 0, CREATE OR REPLACE TABLE | SCHEMA | DATABASE, INSERT OVERWRITE, UNDROP, ALTER ACCOUNT Snowflake CREATE TABLE IF NOT EXISTS and a retention above 0; in CI it is flagged like a DROP TABLE
VERICTO-095 Warehouse cost CREATE|ALTER WAREHOUSE … WAREHOUSE_SIZE | MAX_CLUSTER_COUNT | AUTO_SUSPEND = 0, ALTER RESOURCE MONITOR Snowflake Create the warehouse with the defaults or an AUTO_SUSPEND above 0; size changes go in a reviewed migration
VERICTO-096 Code that runs later CREATE TASK | STREAM | PIPE | PROCEDURE | FUNCTION | ALERT, ALTER TASK … RESUME | MODIFY AS, EXECUTE TASK Snowflake Create tasks and procedures in reviewed migrations; from the application, call them with CALL
VERICTO-097 Role switch USE ROLE, USE SECONDARY ROLES ALL | <roles> Snowflake Connect with the role the application needs; USE SECONDARY ROLES NONE is not reported

Custom rules (YAML)

Builder plans and above allow defining custom rules in YAML. You can create rules that block specific operations on particular tables, without touching your application code.

Custom rules are evaluated after built-in rules with the same latency. The YAML has node_type at the top level and the predicates inside condition:

rule: block-update-on-payments
node_type: UpdateStmt
condition:
  relation: payments

There are eight condition predicates: relation, where_clause, where_always_true, target_list, has_limit, func_name, object_type and alter_kind. Name, severity and dialect do not belong in the YAML: they are form and API fields.

The full reference — the eight node types, the eight predicates and copy-ready examples — is in the custom rules documentation.

Custom rules are hot-loaded without restarting the proxy. The propagation time is under 5 seconds from when you save the file in the dashboard.

Custom rules are managed from the workspace dashboard. From the CLI you can inspect the effective catalogue with vericto rules list and view a rule's detail with vericto rules show <CODE>.

Code index

Code Description Severity Default action
VERICTO-001DELETE without WHERE clauseCRITICALBLOCK
VERICTO-002DELETE with LIMIT 0 (MySQL)HIGHBLOCK
VERICTO-003DELETE with always-true WHERE (1=1, true)CRITICALBLOCK
VERICTO-010DROP TABLE or DROP DATABASECRITICALBLOCK
VERICTO-011TRUNCATE TABLECRITICALBLOCK
VERICTO-012DROP SCHEMACRITICALBLOCK
VERICTO-013DROP INDEX without IF EXISTSHIGHBLOCK
VERICTO-015ALTER TABLE DROP COLUMNHIGHBLOCK
VERICTO-016ALTER TABLE RENAME (table or column)HIGHBLOCK
VERICTO-017ALTER TABLE DROP CONSTRAINT (FK/PK/CHECK)HIGHBLOCK
VERICTO-018ALTER TABLE ALTER COLUMN TYPEHIGHBLOCK
VERICTO-019ALTER TABLE DISABLE TRIGGER / RLSHIGHBLOCK
VERICTO-030UPDATE without WHERE on main tableCRITICALBLOCK
VERICTO-031UPDATE without WHERE inside CTEHIGHBLOCK
VERICTO-033DELETE without WHERE in subquery or CTEHIGHBLOCK
VERICTO-040INSERT INTO … SELECT without filterHIGHBLOCK
VERICTO-042UPDATE without WHERE clauseCRITICALBLOCK
VERICTO-050SELECT without LIMITMEDIUMFLAG
VERICTO-051SELECT * without WHERE clauseMEDIUMFLAG
VERICTO-060INSERT without explicit columnsLOWMONITOR
VERICTO-061INSERT batch with more than 10k rowsMEDIUMFLAG
VERICTO-070Use of SLEEP() or PG_SLEEP()HIGHBLOCK
VERICTO-080COPY … TO/FROM PROGRAM (shell execution)CRITICALBLOCK
VERICTO-081DO anonymous code blockCRITICALBLOCK
VERICTO-082GRANT / REVOKEHIGHBLOCK
VERICTO-083MERGEHIGHBLOCK
VERICTO-084CREATE TABLE AS SELECTHIGHBLOCK
VERICTO-085Read of a sensitive columnHIGHPER TAG
VERICTO-086SQL text that MySQL and the engine would read differently (MySQL)CRITICALBLOCK
VERICTO-090SQL injection: OR tautology in WHERE (OR 1=1)CRITICALBLOCK
VERICTO-091Stage unload or file transfer (Snowflake)CRITICALBLOCK
VERICTO-092External stage or integration (Snowflake)CRITICALBLOCK
VERICTO-093Share to another account (Snowflake)CRITICALBLOCK
VERICTO-094Recovery reduced (Snowflake)HIGHBLOCK
VERICTO-095Warehouse cost (Snowflake)HIGHBLOCK
VERICTO-096Code that runs later (Snowflake)HIGHBLOCK
VERICTO-097Role switch (Snowflake)HIGHBLOCK