Custom Rules.

Define your own deterministic AST conditions to block domain-specific queries that standard rules do not cover.

What are custom rules?

Vericto's standard rules cover the most common destructive patterns (DELETE without WHERE, DROP TABLE, TRUNCATE, etc.). Custom rules let you extend that ruleset with conditions specific to your business, defined through a YAML condition over the query's AST syntax tree.

Like all Vericto rules, custom rules are deterministic: the same input always produces the same result. There are no ML models, no variance. A query either meets the condition or it doesn't, no ambiguity.

Common use cases:

  • Block SELECT * on payment or user tables (prevents mass data exfiltration)
  • Prevent UPDATE without a WHERE clause on high-criticality tables
  • Detect calls to dangerous functions like SLEEP() or PG_SLEEP()
  • Block queries that access internal schemas (information_schema, pg_catalog)
  • Enforce index usage on specific columns (disallow queries without a predicate)

Availability by plan

Custom rules are available starting with the BUILDER plan ($49/mo).

PlanCustom rulesLimit
FreeNot available
Builder ($49/mes)✅ IncludedUp to 50 custom rules
Team ($149/mes)✅ IncludedUnlimited

If you try to create a custom rule on the Free plan, the API responds with 403 Forbidden (code PLAN_UPGRADE_REQUIRED) and an upgrade link.

YAML schema

Each custom rule carries a YAML condition that defines when Vericto should block a query. The YAML must have at least the rule and node_type fields.

rule: nombre-interno-de-la-regla   # identificador libre
node_type: DeleteStmt              # tipo de nodo AST a capturar
condition:
  where_clause: null               # solo si falta WHERE

YAML fields

rule Required string

Internal identifier of the rule. Appears in logs and the audit trail. Use kebab-case, e.g.: block-select-star-payments.

node_type Required string

AST node type that triggers the condition. See available node types.

condition Optional object

Additional predicates on the node. If omitted, the rule fires for all nodes of that type.

message Optional string

Custom message included in the block response and the audit trail.

AST node types

AST nodes represent the type of SQL statement or expression that Vericto detects in the syntax tree. The dialect determines which parser is used (pg_query for PostgreSQL, sqlparser-rs for MySQL).

node_typeDescriptionDialect
DeleteStmtDELETE statementpostgres / all
UpdateStmtUPDATE statementpostgres / all
SelectStmtSELECT statementpostgres / all
InsertStmtINSERT statementpostgres / all
DropStmtDROP statement (TABLE, DATABASE, INDEX, SCHEMA)postgres / all
TruncateStmtTRUNCATE statementpostgres
AlterTableStmtALTER TABLE (DROP COLUMN, RENAME, etc.)postgres
FuncCallSQL function call (SLEEP, PG_SLEEP, etc.)postgres / all

Available conditions

Inside condition: you can use the following predicates depending on the node type:

For any node

PredicateValueMeaning
relation: "nombre"stringScopes the rule to a specific table (case-insensitive; schema is ignored, so public.payments matches payments)

For DELETE / UPDATE / SELECT

PredicateValueMeaning
where_clause: nullnullThe query has NO WHERE clause
where_always_true: truetrueTrivially true WHERE (1=1, true)

For SELECT

PredicateValueMeaning
target_list: "*""*"The query uses SELECT *
has_limit: falsefalseThe query does not include LIMIT

For FuncCall

PredicateValueMeaning
func_name: "nombre"stringName of the function to block (case-insensitive)

For DropStmt

PredicateValueMeaning
object_type: "table""table", "database", "schema", "index"Type of object being dropped

For AlterTableStmt

PredicateValueMeaning
alter_kind: "drop_column""drop_column", "rename", "drop_constraint", "alter_column_type", "disable_trigger"ALTER TABLE command subtype. Without this predicate, the rule fires for any ALTER TABLE.

Practical examples

1. Block SELECT * (mass exfiltration)

rule: block-select-star
node_type: SelectStmt
condition:
  target_list: "*"

Blocks queries like SELECT * FROM users or SELECT * FROM payments. Allows queries with explicit columns like SELECT id, email FROM users.

2. Block UPDATE without WHERE

rule: block-update-no-where
node_type: UpdateStmt
condition:
  where_clause: null

Blocks UPDATE users SET status = 'blocked' but allows UPDATE users SET status = 'blocked' WHERE id = $1.

3. Detect SQL injection tautologies

rule: block-or-tautology
node_type: DeleteStmt
condition:
  where_always_true: true

Blocks queries like DELETE FROM users WHERE id = 1 OR 1=1 by detecting the trivially true OR branch in the AST.

4. Block SLEEP calls (DoS)

rule: block-sleep-calls
node_type: FuncCall
condition:
  func_name: sleep

Blocks SELECT SLEEP(10) (MySQL) and SELECT PG_SLEEP(10) (PostgreSQL) to prevent Denial of Service attacks.

5. Block SELECT without LIMIT

rule: require-limit-on-select
node_type: SelectStmt
condition:
  has_limit: false
message: "Las queries SELECT deben incluir cláusula LIMIT para evitar scans completos de tabla"

Useful for very large tables where a full scan without a limit can significantly degrade performance.

6. Block DROP of any object

rule: block-all-drops
node_type: DropStmt

Without condition:, the rule triggers for any DROP (TABLE, INDEX, SCHEMA). Useful in production environments where no DROP should run from the application.

7. Protect a specific table

rule: protect-payments
node_type: DeleteStmt
condition:
  relation: payments
  where_clause: null

With relation you scope the rule to a single table: it blocks DELETE FROM payments without WHERE, but leaves other tables untouched. Combine any predicate with relation to limit its scope.

8. Block DROP COLUMN

rule: block-drop-column
node_type: AlterTableStmt
condition:
  alter_kind: drop_column

Blocks ALTER TABLE users DROP COLUMN email (irreversible data loss) but allows other changes like RENAME or ADD COLUMN.

Preview before activating

Before saving a custom rule, the dashboard offers a preview that evaluates the YAML against the workspace's historical queries from the last 7 days.

The preview shows:

  • Whether the YAML is valid (validation_result.valid: true/false)
  • How many historical queries this rule would have blocked
  • An example query that triggers the condition
  • List of matching audit trail events

The preview is read-only: it doesn't block anything. The rule only starts blocking queries in real time when you click Create rule.

REST API for custom rules

Create a custom rule

POST /api/v1/workspaces/:workspace_id/rules/custom
Authorization: Bearer <token>

{
  "name": "Bloquear SELECT * en pagos",
  "severity": "warning",
  "dialect": "postgres",
  "ast_condition_yaml": "rule: block-select-star\nnode_type: SelectStmt\ncondition:\n  target_list: \"*\""
}

// Response 201
{
  "rule_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "code": "CUSTOM-001",
  "name": "Bloquear SELECT * en pagos",
  "severity": "warning",
  "is_active": true,
  "created_at": "2025-06-20T10:00:00Z",
  "validation_result": { "valid": true, "errors": [] }
}

Preview before saving

POST /api/v1/workspaces/:workspace_id/rules/custom/preview
Authorization: Bearer <token>

{
  "ast_condition_yaml": "rule: block-select-star\nnode_type: SelectStmt\ncondition:\n  target_list: \"*\"",
  "dialect": "postgres",
  "lookback_days": 7
}

// Response 200
{
  "matching_queries": [...],
  "total_matches": 3,
  "validation_result": { "valid": true, "errors": [] },
  "example_triggering_query": "SELECT * FROM users"
}

Required fields

FieldTypeDescription
namestring (1–128 chars)Descriptive name of the rule
severity"critical" / "warning" / "info"Severity: determines whether it triggers alerts
dialect"postgres" / "mysql" / "all"SQL dialect the rule applies to
ast_condition_yamlstring YAML (10–16384 chars)AST condition that defines when to block

Current limitations

  • YAML conditions only support the predicates documented above: you can't write arbitrary expressions over the AST yet.
  • The condition.table_name field (filter by a specific table name) is on the roadmap but not available yet.
  • Maximum of 50 custom rules on the Builder plan, unlimited on the Team plan.
  • The YAML is validated on the server: a syntactically incorrect YAML returns 400 Bad Request with the validation errors.
  • Custom rules don't support data-modifying CTEs yet (e.g.: WITH x AS (DELETE ...)). Standard rules VERICTO-001 through VERICTO-020 do detect them.

Always use the preview before activating a custom rule in production. A misconfigured rule can block legitimate queries. The Vericto team recommends activating in staging first and validating for 24h before moving to production.

Do you have a use case the current conditions don't cover? Write to us. Real customer cases guide the roadmap for new predicates.