Un firewall SQL determinístico
Vericto no adivina. Parsea cada sentencia a su árbol sintáctico (AST), con pg_query para Postgres y sqlparser-rs para MySQL, Oracle, SQL Server, Snowflake y SQLite, y evalúa sobre ese árbol las reglas activas de tu workspace. Sin ML ni umbrales: el mismo SQL con las mismas reglas da siempre el mismo veredicto. El motor es source-available (ELv2) y está en GitHub.
Qué bloquea y qué marca
| Riesgo | Reglas | Por defecto |
|---|---|---|
DELETE y UPDATE sin WHERE, con un WHERE siempre verdadero (1=1, OR 1=1) o con LIMIT 0 en MySQL | VERICTO-001, 002, 003, 030, 042, 090 | block |
| DROP TABLE, DROP DATABASE y DROP SCHEMA | VERICTO-010, 012 | block |
| TRUNCATE | VERICTO-011 | block |
| DDL riesgoso: DROP INDEX sin IF EXISTS, DROP COLUMN, RENAME, DROP CONSTRAINT, ALTER COLUMN TYPE, DISABLE TRIGGER o ROW LEVEL SECURITY y DROP TRIGGER | VERICTO-013, 015–019 | block |
SELECT sin LIMIT y SELECT * sin WHERE | VERICTO-050, 051 | flag |
Cargas masivas: INSERT de más de 10.000 filas y COPY … FROM un archivo del servidor | VERICTO-061 | flag |
COPY … PROGRAM (un comando de shell en el servidor) y bloques anónimos DO | VERICTO-080, 081 | block |
| GRANT y REVOKE | VERICTO-082 | block |
| MERGE y CREATE TABLE AS SELECT | VERICTO-083, 084 | block |
La acción por defecto sale de la severidad: CRITICAL y HIGH bloquean (block), MEDIUM deja pasar la query y genera una alerta (flag), y LOW e INFORMATIONAL solo la registran (monitor). El owner o un admin del workspace puede cambiar la acción por severidad o empezar en modo observación. Desde el plan Builder puedes sumar reglas propias en YAML.
DROP TRIGGER (VERICTO-019) y COPY … FROM un archivo del servidor (VERICTO-061) se reportan desde la versión 3.9.0 del motor, que el proxy TCP incluye desde su versión 4.9.0. El evaluador de Vericto, que atiende la API, la CLI y MCP, los reporta cuando adopta esa versión del motor.
Así se ve un veredicto
Tres sentencias de un script, evaluadas con check_sql. Cada hallazgo trae la línea, el estado, la regla, la severidad y la corrección sugerida:
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
El DROP TABLE sale FLAGGED porque check_sql es un check de CI. En runtime, la misma sentencia se bloquea.
Dónde se aplica
- Proxy TCP para Postgres y MySQL: se despliega en tu infraestructura y la query bloqueada no llega a la base de datos. La aplicación recibe el error nativo de su driver, SQLSTATE 42501 en Postgres y ERROR 1142 en MySQL, con la regla.
- API de runtime: tu aplicación envía cada query antes de ejecutarla y la ejecuta solo si la respuesta es
200. Sirve también para Oracle, SQL Server, Snowflake y SQLite. - CLI y CI:
vericto checken pre-commit y en el pipeline, o la GitHub Action, que anota los hallazgos en el PR y falla el job ante un bloqueo. - MCP: tu agente de código llama a
check_sqlmientras escribe la migración o la query. Es el mismo motor, así que funciona como firewall de base de datos para agentes de IA antes de que exista un commit.
- uses: vericto/check-sql@v1
with:
api-key: ${{ secrets.VERICTO_API_KEY }}
Dialectos: PostgreSQL, MySQL, Oracle, SQL Server, Snowflake y SQLite. El proxy TCP cubre Postgres y MySQL; la API de runtime, la CLI y MCP, los seis.
En runtime bloquea; en CI, las migraciones informan
Una migración versionada contiene DROP, ALTER y TRUNCATE con toda razón. Por eso, en CI y en MCP las reglas de esquema y DDL (VERICTO-010 a 019) se limitan a flag (schema_migration_cap): el pipeline reporta el hallazgo y no falla. El DML destructivo, como un DELETE sin WHERE, y las reglas de seguridad mantienen en CI la acción de tu workspace. En el proxy TCP y en la API de runtime, todas las reglas aplican su acción completa.
Límites
- Una sentencia que no se puede parsear se reenvía y queda registrada como
PARSE_ERROR(fail-open) por defecto, para no cortar el tráfico. El owner o un admin puede pasar el workspace a fail-closed. - En MySQL, el texto que MySQL y el motor podrían leer distinto, por sus comentarios ejecutables y sus escapes de string, siempre se bloquea (VERICTO-086). Esa regla no se desactiva ni baja de severidad.
- Vericto lee el SQL, no tu esquema ni tus datos: una tautología que depende de los valores de una columna, como
WHERE id = 1 OR id > 0, queda fuera de su alcance. - Es defensa en profundidad: los roles, los permisos y los backups de tu base de datos siguen siendo necesarios.
Las reglas estándar están en todos los planes, también en Free. Las reglas custom en YAML están desde el plan Builder.