ShipGuardScan a site

Lovable + Supabase RLS Checklist Before You Launch

Updated 2026-10-17

Lovable apps typically talk to Supabase directly from the browser using the project URL and the public anon (publishable) key. That is a supported pattern — but only if Row Level Security (RLS) is enabled with correct policies on every table the anon role can reach. This checklist walks through what to verify before real users arrive.

Why RLS is the whole security model

The anon key is designed to be public. Anyone can copy it from your JavaScript bundle and call your Supabase REST endpoint directly, bypassing your UI entirely. What they can read or write is decided only by Postgres grants and RLS policies.

If a table in the exposed schema has RLS disabled, the anon and authenticated roles can usually read and modify every row in it. Supabase's dashboard warns about this, but generated projects can still ship with tables created later without policies.

Enable RLS and add owner policies

For a typical user-owned table, enable RLS and scope every operation to the signed-in user.

alter table public.notes enable row level security;

create policy "owners read" on public.notes
  for select using (auth.uid() = user_id);
create policy "owners insert" on public.notes
  for insert with check (auth.uid() = user_id);
create policy "owners update" on public.notes
  for update using (auth.uid() = user_id) with check (auth.uid() = user_id);
create policy "owners delete" on public.notes
  for delete using (auth.uid() = user_id);

Test like an attacker (with your own project)

Open your browser devtools on your own app, copy the anon key, and query each table with curl. Every table should return only rows the policy allows — for an unauthenticated request that is usually nothing.

Repeat signed in as a second test user and confirm you cannot read the first user's rows.

curl "https://<project-ref>.supabase.co/rest/v1/notes?select=*" \
  -H "apikey: <anon-key>" -H "Authorization: Bearer <anon-key>"

Checklist

  • RLS enabled on every table in the public schema
  • Policies exist for select / insert / update / delete where needed
  • with check clauses prevent writing rows for other users
  • No using (true) policies on private data
  • Storage buckets private unless they must be public
  • service_role key never appears in client code
  • Internal tables moved to a non-exposed schema

Copy-paste fix prompt

Audit my Supabase schema: list every table in `public`, enable Row Level Security on each, and generate owner-scoped select/insert/update/delete policies using `auth.uid() = user_id`. Flag any table that has no user_id column so I can decide its policy manually.

FAQ

Is it safe that my Supabase anon key is visible in the browser?

Yes, the anon/publishable key is meant to be public. Safety depends entirely on RLS policies and grants. The service_role or sb_secret_ key must never be public.

Can a passive scanner prove my RLS is broken?

No. A passive scanner can see whether your schema is enumerable and whether keys are exposed, but it does not read your rows, so it cannot confirm whether policies are effective. Test with the anon key against your own project.

Check your deployed app in ~25 seconds

Free passive scan: leaked keys, Supabase exposure, public config files and headers.

Run a free scan