RLS Radar

Supabase RLS checklist for vibe-coded apps

By RLS RadarUpdated Reviewed against official Supabase docs
Short answer

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

  1. List every table in public (and any other exposed schemas).
  2. List every storage bucket and whether it is marked public.
  3. Confirm the browser only receives the anon / publishable key — never service_role or sb_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

  1. Default buckets to private.
  2. Use signed URLs for private objects.
  3. Add storage policies scoped to auth.uid() path prefixes.

5. Re-test from the outside

  1. Open your shipped URL in a private window.
  2. Run RLS Radar (permission required) for key leaks + defensive accessibility signals.
  3. In Supabase SQL, review pg_policies for surprises.
Scan your app free →

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

Check your live app in seconds

Free, read-only, permission-gated. Nothing stored.

Scan your app

Related guides