Materialized views and foreign tables are not readable through the API
Why it matters
Row-level security is not supported on materialized views or foreign tables, so neither can be protected by policies. A materialized view created in public is queried through the REST endpoint like any table, and by default anon and authenticated hold SELECT on it, so a cached aggregate or a snapshot of user data is readable by anyone and nothing in your RLS setup applies. A foreign table (a postgres_fdw or other wrapper to another database or an external API) exposes the remote data the same way, along with whatever credentials the wrapper uses. These objects feel internal ('just a reporting rollup') and AI tools place them in public because that is where the migration is already working. The advisor reports them as lints 0016 and 0017.
Severity rationale
Medium because the exposure requires such an object to exist and to hold sensitive data, and the usual content is aggregated or derived, but when it does hold row-level data there is no policy layer to stop reads.
Remediation
Keep these objects out of the API. Create them in a non-exposed schema, or revoke the API roles' access, and expose the data through a security_invoker view or a checked function when clients need it:
create materialized view private.daily_signups as
select date_trunc('day', created_at) as day, count(*) from public.profiles group by 1;
-- or, if it must stay in public
revoke all on public.daily_signups from anon, authenticated;
For a foreign table, create it in a private schema (create foreign table private.remote_orders ...) and never grant it to anon or authenticated.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Supabase RLS & Keys audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe:4.14 · CWE-284 — Improper Access Control
- cwe:4.14 · CWE-285 — Improper Authorization
- owasp:2021 · A01 — Broken Access Control
- external · 0016_materialized_view_in_api — Supabase database advisor lint 0016 materialized view in API
- external · 0017_foreign_table_in_api — Supabase database advisor lint 0017 foreign table in API
Taxons
History
- 2026-10-03·v1.0.0·Initial supabase-rls-keys v1 authoring; materialized views and foreign tables in exposed schemas must not be readable by anon or authenticated. Materialized views over auth.* are reported by auth-users-not-exposed-via-view.·by supabase-rls-keys-v1-build