Supabase RLS check: is your database open to everyone?
Your Supabase anon key ships inside your frontend, so anyone can grab it. That's by design, and Row Level Security is the only thing between that key and your data. If a table has RLS off, or a policy says using (true), that table is effectively public.
We scanned 21 public vibe-coded apps: 57% had at least one Supabase policy open to everyone, 62% had committed a .env file, and 24% failed a clean npm install. The average launch health was 63/100.
01Find tables with RLS off
- Run this in the Supabase SQL editor:
Any row returned is a table the anon key can read and write freely.select tablename from pg_tables where schemaname = 'public' and rowsecurity = false; - Fix each one:
With RLS on and no policies, nobody can access it via the API. Then add policies for what should be allowed.alter table public.your_table enable row level security;
02Find policies open to everyone
- List them:
select tablename, policyname, cmd, roles, qual, with_check from pg_policies where schemaname = 'public' and (qual = 'true' or with_check = 'true'); - For each one, ask whether a logged-out stranger should be able to do this. Public product lists: fine. Profiles, orders, messages, payments: not fine.
- Replace with an ownership check:
drop policy "Anyone can read" on public.orders; create policy "Users read own orders" on public.orders for select using (auth.uid() = user_id);
03Check the things around RLS
- The
service_rolekey bypasses RLS entirely. Make sure it's only used in edge functions/servers, never insrc/. - Views can bypass RLS. On Postgres 15+, create them with
with (security_invoker = true). security definerfunctions run with elevated rights, so check they validateauth.uid()themselves.- Storage: private buckets need policies on
storage.objectstoo.
04Prove it
- Open your app logged out, then in the browser console run
supabase.from('orders').select('*'). You should get an empty result or an error. - Log in as user A and try to read user B's rows. It should fail.
- Keep RLS in your migrations (
supabase/migrations) so new environments are secure by default.
Don't want to check all this by hand?
Paste your GitHub link. VibeHP runs every check on this page (plus a git-history secret scan and a real build) and gives you an HP score out of 100, with a copy-paste AI prompt for every fix.
Check my HP for $19 →One-time · Your code is deleted right after the scan
FAQ
What does using (true) mean in Supabase?+
It's a policy condition that's always true, so every request (including logged-out users with the anon key) passes. It's only appropriate for genuinely public data.
Is it safe to expose the Supabase anon key?+
Yes, if RLS is enabled with proper policies on every table. The anon key is meant to be public; RLS is what protects your data.
Does VibeHP check my live database?+
Not yet. VibeHP reads your migration files to find tables without RLS and always-true policies. Use the SQL on this page to confirm against your live project.