Skip to content
SSShipSafeStack

Checklist

Supabase row-level security checklist

What to verify on Supabase before a Lovable, Bolt, or other client is allowed to talk to the database with the anon key.

Updated 16 Oct 2026

This is a practical checklist, not a guarantee. It is not a penetration test, a compliance audit, or proof that an app is safe to launch.

Supabase gives the browser a publishable anon key. That key is supposed to be public. Row Level Security is what stops it from reading every row. Many generated apps create tables and forget the policies.

Official reference: Supabase Row Level Security.

On every table in public

  • Open the table in the Supabase dashboard and confirm RLS is enabled. A table with RLS off is readable and writable by anyone who has the anon key and the URL.
  • Do not “fix” a failing query by disabling RLS. Fix the policy, or move the query to a server that uses the secret key.
  • Add separate policies for select, insert, update, and delete. A policy that only covers select still lets a client insert rows.
  • Write the condition so it checks auth.uid() against an owner column, or membership in a team table. using (true) allows every signed-in user, and sometimes every request.

Keys

  • The anon key may live in the frontend. The service_role key must not. Search the client bundle and the repo. If the service role key has been in the browser or in git, rotate it in the Supabase dashboard and update only the server environment.
  • Prefer the server, or a Supabase Edge Function, for anything that must bypass RLS. The bypass is the dangerous part. Keep it small.

Prove it with two users

  • Create two accounts. As user A, insert a row. As user B, request that row with the same anon key the app uses. You should get nothing back.
  • Repeat while logged out. The anon key alone should not return user A’s rows.
  • Read the response in the browser network panel. A 200 with an empty array is a pass. A 200 with the other user’s email is a fail.

Storage and views

  • Check Storage buckets. A private table with a public bucket still exposes files.
  • Views and functions can bypass your expectations. If a view is owned by a privileged role, RLS on the underlying table may not protect the view. Test the view with the anon key too.

After you change a policy

  • Re-run the two-user test. Builders regenerate client code. They do not always regenerate policies, and a later prompt can add a table with RLS off.
Not a guarantee. Policies can be wrong in ways a two-user test does not catch, including joins and functions. This is a checklist, not a database audit.