Security Model

The AI can generate SQL, but it can never act outside the sandbox.

1. Read-only role

AI, chart, and browse queries run on the lizard_read role. Writes (CRUD forms only) use lizard_write with parameterized queries — model SQL never reaches a write-capable connection.

2. SQL Guard

Every AI, chart, and federated query is parsed and validated: single SELECT only. Multi-statements, DML/DDL, comments, pg_sleep, file/dblink/backend-control functions, sequence manipulation, row locking, COPY, and — on the federation path — ATTACH/INSTALL/file readers are all rejected. A hard LIMIT wrapper caps every result.

3. Belt and suspenders

Guarded queries additionally run inside a read-only transaction with a statement timeout (30s for Postgres/MySQL, 45s for federated DuckDB queries). Federation attaches every database READ_ONLY and locks DuckDB's configuration and filesystem access before model SQL runs. Cancelling a running query (the client Stop button, or the request disconnecting) destroys the underlying connection immediately rather than waiting it out.

4. Transparency

The generated SQL and the set of databases touched are always shown in the UI — editable and re-runnable — and everything is recorded in the audit log.

5. Credentials encrypted at rest

Database passwords Lizard stores are encrypted with AES-256-GCM under LIZARD_ENCRYPTION_KEY; the server refuses to start without one. This protects file escaping — a backup, a volume snapshot, a copy of data/ pulled for debugging, or anyone with disk read access but not the process environment. It does not protect against a compromised host or code execution inside Lizard. Passwords never leave the API and never reach query logs.

6. Adversarial test suite

npm test runs 30+ injection/escape vectors against the guard.

Audit log retention

Reads (query, query_cached, federated_query) are machine-driven telemetry, kept 30 days by default. Writes (create, update, delete, import) plus anything that errored are the audit trail proper — kept 365 days by default. A row cap applies on top of both windows; whichever limit is stricter wins.