Schemas beyond public exposed through the data API
Part of the Auth hardening & exposure config check · fix arrives as a guide
What it is
Schemas beyond public are exposed through the Data API.
Why it matters
Those schemas usually hold the things deliberately kept out of the API — internal tables, audit records, staging data — and exposing them makes all of it reachable with an anon or authenticated key, subject only to RLS that may never have been written for them.
Check what your API exposes right now
The list is at Project Settings → API → Exposed schemas. Anything on it is queryable through PostgREST by anyone holding the anon key — they just have to name the schema:
curl "https://YOUR-PROJECT.supabase.co/rest/v1/events?select=*" \
-H "apikey: $ANON_KEY" \
-H "Accept-Profile: analytics" # ← schema selector; try each exposed schemaIf a schema you think of as internal answers that request, this finding is not theoretical.
How internal schemas end up exposed
Someone needed one table from analytics in the app, exposing the schema was the one-line change that worked, and the ticket closed. But exposure is per-schema while security is per-table: every table in that schema is now reachable, under whatever grants and RLS each happens to have — and internal schemas are exactly where RLS was never enabled, because “it’s internal”.
Fix it manually
Pull the schema back to the app through views in public rather than pushing the schema out to the API:
-- expose one table's safe surface, not the schema
create view public.daily_signups
with (security_invoker = true) as
select day, count
from analytics.daily_signups
where day > now() - interval '90 days';
-- then remove `analytics` from Exposed schemas in the API settingsIf a second schema genuinely must be exposed, treat it like public: RLS enabled on every table, policies per command and role, and the same review bar for new tables from then on.
How lumioguard fixes it
The scan reads the exposed-schema list and audits RLS coverage for every table in each — the finding names the tables reachable without policies. The fix arrives as a guide: which schema to unexpose, or the view-based surface to build if the data is genuinely needed.
Run them all on your app
Connect your repo and your live services with read-only scopes. The first scan is free, and nothing changes without your approval.