Skip to content

CREATE VIEW over sqlite_master bypasses --hide-internal-tables #86

Description

@erans

Follow-up from #80 / #85.

--hide-internal-tables rewrites sqlite_master references only in read contexts — Statement::Query and the source of Statement::Insert (src/translator/sqlite_master_filter.rs). CREATE VIEW ... AS SELECT and CREATE TABLE ... AS SELECT are not rewritten.

So with the flag on:

CREATE VIEW v AS SELECT name FROM sqlite_master;
SELECT * FROM v;  -- returns the unfiltered catalog, including __pgsqlite_* rows

The second query never mentions sqlite_master, so nothing filters it — the view is materialized against the real catalog once and reads through it thereafter.

Why it is scoped this way

The restriction to read contexts was added deliberately in #85. Before it, DELETE FROM sqlite_master WHERE name='zzz' was rewritten into syntactically invalid SQL that pasted the internal prefix into the client-facing error:

SQLite error: near "(": syntax error in DELETE FROM (SELECT * FROM sqlite_master WHERE SUBSTR(name, 1, 11) <> '__pgsqlite_' ...

Narrowing to read contexts fixed that but dropped CTAS/CREATE VIEW along with the write statements.

Severity

Not a security hole. The design (docs/superpowers/specs/2026-08-05-hide-internal-tables-design.md) states hiding is listing-only and SELECT * FROM __pgsqlite_schema keeps working by name, so nothing is exposed that was otherwise unreachable. But the flag exists to stop end users stumbling onto internal tables and concluding their data is corrupt, and a schema browser that creates views would defeat that.

Possible fix

Extend the rewrite to the query of Statement::CreateView and Statement::CreateTable's AS SELECT source, keeping Update/Delete excluded. EXPLAIN and DECLARE ... CURSOR are also currently excluded and do not matter — pgsqlite has no handler for either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions