Supabase RLS checklist for vibe-coded apps
Turn on Row Level Security for every table in an exposed schema, revoke grants the anon role should not have, replace USING (true) on private data with auth.uid() ownership policies, make storage buckets private, then re-test from the outside. The publishable/anon key is safe to ship only when all of that is in place.
Your anon (publishable) key is meant to be public. That is fine — only if every table and storage path is locked with Row Level Security. Supabase's own docs warn that a table in an exposed schema without RLS is readable and writable by any role with a grant on it (source).
1. Inventory
- List every table in
public(and any other exposed schemas). - List every storage bucket and whether it is marked public.
- Confirm the browser only receives the anon / publishable key — never
service_roleorsb_secret_.
2. Turn RLS on — everywhere
alter table public.your_table enable row level security; -- repeat for EVERY table the anon key can see
-- RLS does not remove grants. Revoke what anon should not have: revoke all on table public.your_table from anon, authenticated; grant select, insert, update, delete on table public.your_table to authenticated;
RLS off = any client with the anon key can read/write according to GRANTs (often too open in tutorials).
3. Kill blanket policies
Search for policies like USING (true) or WITH CHECK (true) on user data. Replace with ownership checks:
-- example pattern (adapt to your schema) create policy "users read own rows" on public.profiles for select to authenticated using ((select auth.uid()) = user_id);
Public marketing content can stay open; user PII, messages, trading notes, game saves — must not.
Teams, workspaces or orgs? See RLS policies for multi-tenant apps for membership-based policies.
4. Storage
- Default buckets to private.
- Use signed URLs for private objects.
- Add storage policies scoped to
auth.uid()path prefixes.
5. Re-test from the outside
- Open your shipped URL in a private window.
- Run RLS Radar (permission required) for key leaks + defensive accessibility signals.
- In Supabase SQL, review
pg_policiesfor surprises.
Copy-paste fix prompt
Audit my Supabase schema: enable RLS on all public tables, remove USING(true) on sensitive data, add auth.uid() ownership policies with WITH CHECK on writes, lock storage buckets, and confirm no service_role key is in the frontend. Output SQL migrations.
Sources
- Supabase docs: Row Level Security (checked 2026-10-16)
- Supabase docs: API keys (checked 2026-10-16)
- Supabase docs: Storage access control (checked 2026-10-16)
Free, read-only, permission-gated. Nothing stored.