Home / RLS / Why is my table public? (RLS off)
Supabase RLS · Leak
Why is my Supabase table public? (RLS is off)
Your anon key is public (it ships in the browser). With RLS off, that key can read the whole table over the REST API. Confirm with one curl, then enable row level security and add a policy.
01 The anon key is public — that's by design
Supabase's anon key is meant to ship in your frontend. It's not a secret. The thing that stops it from reading everyone's data is RLS. So a table with RLS off is readable by anyone who opens your site's network tab and copies that key. This is the single most common Supabase data leak.
02 See the leak in one command
terminal
# with RLS off, the public anon key returns every row curl "$SUPABASE_URL/rest/v1/notes?select=*" \ -H "apikey: $ANON_KEY" -- → returns ALL rows, from every user
If that returns data you expected to be private, the table is public.
03 Confirm which tables are exposed
audit.sql
select tablename from pg_tables t join pg_class c on c.relname = t.tablename where t.schemaname = 'public' and c.relrowsecurity = false; -- RLS is off
04 Close it
migration.sql
alter table notes enable row level security; create policy "owner reads own notes" on notes for select using (user_id = (select auth.uid()));
Then re-run the curl as an anonymous caller — it should now return an empty set. To make sure a new table can never ship like this again, add an RLS gate in CI.
Catch this before it ships
airlock-rls is a CI gate that fails your build when a table ships exposed or a policy is permissive — the same class of bug, caught on the pull request instead of in prod.
Or start from nextjs-supabase-starter — auth + a table with RLS + an isolation test, so a fresh table is safe by default.
Grab the Supabase RLS cheat sheet
The golden rules, the footguns that leak in prod, correct policy snippets, and the isolation test — on one page.
FAQ
Isn't the anon key protected by my app's login?
No. The anon key works without any login — that's what 'anonymous' means. Your app's login controls your UI, not the REST API. Anyone can call the API directly with the anon key; RLS is what makes that safe.
Should I hide the anon key instead of enabling RLS?
You can't — it ships to every browser that loads your app. Hiding it is impossible and unnecessary. Enable RLS and the public anon key becomes harmless.