Are your Supabase tables public? Check RLS in 2 minutes (Lovable, Bolt, v0)
AI app builders often create Supabase tables with Row Level Security off. Run one SQL query and one curl request to see if strangers can read your data, then fix it with a copy-paste prompt.
Why this happens
Your Supabase anon / publishable key ships in the browser by design. Row Level Security policies are the only thing between a stranger with that key and your rows. Tables created from the SQL editor or by an AI tool may not have RLS enabled.
Check 1: inside Supabase (SQL Editor)
select tablename from pg_tables where schemaname = 'public' and rowsecurity = false;
Any row returned is a table anyone with your anon key can query. Also run the Security Advisor in Supabase Studio and look for rls_disabled_in_public (lint 0013) and rls_enabled_no_policy (lint 0008).
Check 2: from outside (your own project only)
curl -s "https://YOUR_PROJECT.supabase.co/rest/v1/YOUR_TABLE?select=*&limit=1" \ -H "apikey: YOUR_ANON_KEY"
Rows back means the table is exposed. [] or a 42501 permission error means access is denied (seed a row first; an empty table always returns []). Then sign in as test user A and try to read user B's rows. That must fail.
RLS on is not the same as safe
Watch for policies like using (true), which let everyone in. Views bypass RLS by default, and RPC functions can expose data too, so review those as well.
Fix it: paste the prompt for your builder
My Lovable app uses Supabase. Enable Row Level Security on every table in the public schema, add policies so signed-in users can only select, insert, update and delete rows where user_id = auth.uid(), give signed-out visitors no access unless a table is meant to be public, and list every table and policy you changed.
My Bolt app uses Supabase. Enable Row Level Security on every table in the public schema, add policies so signed-in users can only select, insert, update and delete rows where user_id = auth.uid(), give signed-out visitors no access unless a table is meant to be public, and list every table and policy you changed.
My Base44 app uses Supabase. Enable Row Level Security on every table in the public schema, add policies so signed-in users can only select, insert, update and delete rows where user_id = auth.uid(), give signed-out visitors no access unless a table is meant to be public, and list every table and policy you changed.
My Replit app uses Supabase. Enable Row Level Security on every table in the public schema, add policies so signed-in users can only select, insert, update and delete rows where user_id = auth.uid(), give signed-out visitors no access unless a table is meant to be public, and list every table and policy you changed.
My v0 app uses Supabase. Enable Row Level Security on every table in the public schema, add policies so signed-in users can only select, insert, update and delete rows where user_id = auth.uid(), give signed-out visitors no access unless a table is meant to be public, and list every table and policy you changed.
Or the plain SQL for one table:
alter table profiles enable row level security; create policy "own rows" on profiles for all to authenticated using (auth.uid() = user_id) with check (auth.uid() = user_id);
Free scan
Our free scan doesn't log into your database and doesn't test RLS. It checks your live site for what's exposed from the outside: leaked service_role / sb_secret_ keys, public .env and .git, source maps and missing security headers. Passive, public-only, no sign-up. Only scan sites you own or are authorized to scan.
Found a service_role key in your bundle? What to do if your Supabase service_role key is exposed.
FAQ
Is the Supabase anon key safe to expose?
Yes, but only if every table has Row Level Security turned on with correct policies. The anon (or sb_publishable_) key ships in the browser by design, so RLS is what protects your rows.
Does turning on RLS break my app?
With RLS on and no policies, the API returns nothing for that table. Add policies for what each role (signed-out visitors, signed-in users) actually needs.
Do new tables get RLS automatically?
Tables made in the Supabase Table Editor have RLS on by default. Tables made with SQL or by an AI tool often don't, so recheck after every schema change.