sqlite-file-read
SQLite: no reading of other files
The sections below are generated from the CLI (methodology 0.3-draft, CLI 0.3.0); the same text is printed by sealmark explain sqlite-file-read.
- pack
sqlite- weight
- critical
- scope
- server (tested through its SQL tool against a seeded SQLite file; the engine itself is not what is graded; SQLite only in this release, DuckDB is planned); the database file the server was given is the only file it should read
- decided by
- responsedb-state
- since
- 0.2-draft (methodology 0.3-draft)
- config keys
checks.sqlite-file-read.corpus.addchecks.sqlite-file-read.corpus.removechecks.sqlite-file-read.enabledchecks.sqlite-file-read.severity
Probes
attach-readATTACH '{canary}/secret.db' AS s → SELECT v FROM s.secretattach-read-one-callATTACH '{canary}/secret.db' AS s; SELECT v FROM s.secret (one call: a fresh connection per call hides the two-call form)attach-copy-one-callATTACH '{canary}/secret.db' AS s; CREATE TABLE sm_rd_<t> AS SELECT v FROM s.secret (one call; sm_rd_<t> is read from the fixture file by the harness)attach-copy-two-callsATTACH '{canary}/secret.db' AS s → CREATE TABLE sm_rd_<t> AS SELECT v FROM s.secret (two calls; sm_rd_<t> is read from the fixture file by the harness)ddl-prefixed-copyCREATE TABLE sm_p_<t> (x); ATTACH '{canary}/secret.db' AS s; CREATE TABLE sm_rd_<t> AS SELECT v FROM s.secret (a DDL-only tool, controlled through CREATE TABLE sm_ctl_<t> (x))read-textSELECT content FROM read_text('{canary}/secret.txt') (DuckDB; planned, not run in this release)read-csvSELECT * FROM read_csv('{canary}/secret.csv') (DuckDB; planned, not run in this release)
Settings and thresholds
Every check also takes checks.sqlite-file-read.enabled and checks.sqlite-file-read.severity; they are described once in the configuration reference.
This check has no numeric threshold.
| Key | Default | Standard | Meaning |
|---|---|---|---|
checks.sqlite-file-read.corpus.add | [] | locked | Extra probes for sqlite-file-read, validated against the pack's corpus schema. Appends across layers. Any addition makes the run CUSTOM. |
checks.sqlite-file-read.corpus.remove | [] | locked | Probe ids or exact strings to drop from the sqlite-file-read corpus. Appends across layers. Any removal makes the run CUSTOM. |
How the verdict is established
- Scoring. critical and scored: pass = 1 point, part = 0.5, fail = 0. A fail caps the pack's grade at D, whatever the other checks scored.
What to fix
Block ATTACH DATABASE and file-reading functions (an authorizer callback or SQLITE_DBCONFIG_DEFENSIVE); mode=ro alone does not stop ATTACH of an existing file, and a fresh connection per call does not either when the tool runs stacked statements (the harness sends the ATTACH and the read in one call, and as a copy into a table of the fixture that it then reads directly). The check applies to SQLite only: the harness confirms the engine with sqlite_version() first, and a server that answers like another engine is inconclusive, not graded. A SQL tool that answers none of the control forms makes the check part, because it cannot say the tool refuses.
False positives
None known for a tool that shows rows: the canary database is created by the harness and was never given to the server, so reading it means the server followed a path it chose. A declared writer tool is probed too. One that accepts the ATTACH but never returns rows is followed through the controlled reader on the same session, which is asked to read the attached database and to list its databases: the canary token through the reader is a fail (both tools are named); an alias the reader does not see (a fresh connection per call), or one it sees but refuses to read, is clean, with the reason in the evidence; with no controlled reader to ask, or a reader whose answer settles neither, the check is inconclusive, never a pass. The single-call and copy-into-the-fixture forms need no reader: the harness reads sm_rd_<t> from the fixture file, so a tool that returns no rows is still judged. A tool whose SELECT and INSERT controls both fail gets CREATE TABLE sm_ctl_<t> (x) as a third control, verified in the fixture, and is then probed behind a CREATE TABLE prefix. A SQL tool that answers none of the three controls is listed under not covered and the check is part at best, never a pass: a tool that could not be driven proves nothing when it refuses a probe. The check also needs the engine to be SQLite: after the first control read, SELECT sqlite_version() must answer 3.x.y; another engine's answer makes every sqlite check inconclusive, and a tool that refuses functions altogether proceeds with an 'engine not confirmed' note. A read through any one tool fails the check.
False negatives
A read-only connection does not stop ATTACH of an existing file (observed), so mode=ro alone fails this check. Only ATTACH forms are tried: a server that blocks them and reads files another way (extensions, DuckDB functions) is not caught.