A deterministic SQL firewall
Vericto does not guess. It parses each statement into its syntax tree (AST), with pg_query for Postgres and sqlparser-rs for MySQL, Oracle and SQL Server, 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 source-available (ELv2) and on GitHub.
What it blocks and what it flags
| Risk | Rules | Default |
|---|---|---|
DELETE and UPDATE without WHERE, with an always-true WHERE (1=1, OR 1=1) or with LIMIT 0 on MySQL | VERICTO-001, 002, 003, 030, 042, 090 | block |
| DROP TABLE, DROP DATABASE and DROP SCHEMA | VERICTO-010, 012 | block |
| TRUNCATE | VERICTO-011 | block |
| Risky DDL: DROP INDEX without IF EXISTS, DROP COLUMN, RENAME, DROP CONSTRAINT, ALTER COLUMN TYPE, DISABLE TRIGGER or ROW LEVEL SECURITY, and DROP TRIGGER | VERICTO-013, 015–019 | block |
SELECT without LIMIT and SELECT * without WHERE | VERICTO-050, 051 | flag |
Bulk loads: INSERT of more than 10,000 rows and COPY … FROM a file on the server | VERICTO-061 | flag |
COPY … PROGRAM (a shell command on the server) and anonymous DO blocks | VERICTO-080, 081 | block |
| GRANT and REVOKE | VERICTO-082 | block |
| MERGE and CREATE TABLE AS SELECT | VERICTO-083, 084 | block |
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.
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: 2 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 FLAGGED 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 FLAGGED because check_sql is a CI check. At runtime, the same statement is blocked.
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 and SQL Server. - CLI and CI:
vericto checkin 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_sqlwhile it writes the migration or the query. It is the same engine, so it works as a database firewall for AI agents before a commit exists.
- uses: vericto/check-sql@v1
with:
api-key: ${{ secrets.VERICTO_API_KEY }}
Dialects: PostgreSQL, MySQL, Oracle and SQL Server. The TCP proxy covers Postgres and MySQL; the Runtime API, the CLI and MCP cover all four.
At runtime it blocks; in CI, migrations report
A versioned migration has every reason to contain DROP, ALTER and TRUNCATE. So in CI and MCP 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. Destructive DML, such as a DELETE without WHERE, and the security rules keep your workspace's action in CI. In the TCP proxy and the Runtime API, every rule applies its full action.
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.