AST rules reference

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 Acción por defecto Behavior Alerts
CRITICAL BLOCK Immediate block of the query. SQLSTATE 42501 to the client. Alerta en tiempo real via webhook y dashboard
HIGH BLOCK Query blocked, fully recorded in the audit trail. Alerta en tiempo real
MEDIUM FLAG The query is forwarded upstream. Logged and alerted on, but not blocked. Alerta (FLAG) en dashboard y webhook
LOW MONITOR The query is forwarded. Recorded in telemetry only, no alert. Solo telemetría / audit trail
INFORMATIONAL MONITOR The query is forwarded. Informational logging, no action. Solo métricas

Builder plans and above allow changing the behavior of any rule between block (block) and log-only (record without blocking). This is useful during the adoption period 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 (excluye 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 (incluye WHERE trivial) 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

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 o 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

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).

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. Example custom rule:

id: CUSTOM-001
name: Bloquear UPDATE en tabla payments
severity: critical
dialect: postgres
condition:
  node: UpdateStmt
  relation: payments
message: "Las actualizaciones en la tabla payments requieren revisión manual"

The available condition fields are:

  • node: AST node type (e.g. UpdateStmt, DeleteStmt, SelectStmt)
  • relation: exact table name (optional)
  • where_null: true to require the absence of a WHERE clause
  • columns: list of columns that trigger the rule (optional)

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 Acción por defecto
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-090SQL injection: OR tautology in WHERE (OR 1=1)CRITICALBLOCK