Supabase RLS not working in your Lovable, Bolt, or Cursor app
Users can see each other's data, or every query returns nothing. How to check and fix Supabase Row Level Security in an AI-built app.
What you are seeing
- A second test account can read or edit the first account's rows.
- After you turn RLS on, every select returns an empty array and nothing errors.
- Inserts fail with "new row violates row-level security policy".
Why it happens
- RLS is disabled on the table, so the public anon key can read everything.
- RLS is enabled but there is no policy for that operation, so Postgres denies it silently (selects come back empty).
- The policy compares the wrong column, for example
id = auth.uid()when the owner column isuser_id. - The insert does not set
user_id, so thewith checkclause fails. - The service role key was used in the browser to "make it work", which bypasses RLS entirely and exposes the database.
How to fix it
1. Check which tables have RLS off
select tablename, rowsecurity from pg_tables where schemaname = 'public';
2. Turn it on for each user table
alter table public.todos enable row level security;
3. Add owner policies for read and write
create policy "owner can read" on public.todos
for select using (auth.uid() = user_id);
create policy "owner can insert" on public.todos
for insert with check (auth.uid() = user_id);
create policy "owner can update" on public.todos
for update using (auth.uid() = user_id) with check (auth.uid() = user_id);
create policy "owner can delete" on public.todos
for delete using (auth.uid() = user_id);
4. Default the owner column so inserts pass
alter table public.todos alter column user_id set default auth.uid();
5. Search the frontend for the service role key
grep -rn "service_role\|SERVICE_ROLE" src/ app/ .env* 2>/dev/null
How to know it is fixed
Sign in as two different test users in two browsers. Each should see only their own rows, and a direct REST call with the anon key and no session should return nothing.