How to fix Supabase RLS in a Lovable app
Lovable, Bolt and v0 make it easy to ship a Supabase-backed app in an afternoon. The catch: the public anon key is in your front end by design, so the only thing standing between a visitor and your whole database is row-level security (RLS). If RLS is off, or a policy says using (true), anyone can read and edit every row.
1. Find tables without RLS
select schemaname, tablename, rowsecurity
from pg_tables where schemaname = 'public' order by tablename;
Any row with rowsecurity = false holding user data is exposed.
2. Remove “Enable all access” style policies
select tablename, policyname, qual, with_check from pg_policies where schemaname = 'public';
-- then, for each permissive one:
drop policy "Enable all access" on public.notes;
3. Enable and force RLS
alter table public.notes enable row level security;
alter table public.notes force row level security;
4. Add owner-only policies
create policy "own notes read" on public.notes for select to authenticated using (user_id = auth.uid());
create policy "own notes insert" on public.notes for insert to authenticated with check (user_id = auth.uid());
create policy "own notes update" on public.notes for update to authenticated using (user_id = auth.uid()) with check (user_id = auth.uid());
For tables like orders, give users read-only access and let only your server (webhook) change status.
5. Revoke anon access to private tables
revoke all on public.notes, public.orders from anon;
6. Verify like an attacker
curl "$SUPABASE_URL/rest/v1/notes?select=*" -H "apikey: $ANON_KEY"
# expect: []
Then sign in as a normal user and confirm they still see (only) their own data. Skipping this step is how “fixes” break apps.
Put it in a migration (e.g. supabase/migrations/002_rls.sql) so it is reviewable and repeatable, not clicked in the dashboard.