Guide · Supabase

Supabase RLS: can a stranger read your database?

Short answer: Your Supabase anon (or publishable) key is in your website on purpose, so anyone can use it. Row Level Security is the only thing that decides what that key can read and write. Check that RLS is enabled on every table in the public schema, that each table has policies limiting rows to their owner, and then test it: ask for a sensitive table with only the anon key, signed out. If you get rows or a count back, a stranger can too.

Updated 25 October 2026

What to do, step by step

Supabase exposes every table in the public schema through its API. A table without RLS is readable and writable by anyone holding the anon key, which is everyone who has loaded your site.

  1. Look at the Security Advisor

    In the Supabase dashboard, open Advisors → Security Advisor. Any "RLS disabled in public" or "Policy exists RLS disabled" item is a table open to the world. Fix those first.

  2. List every table and its RLS status

    Run this in the SQL editor. Every row should say true:

    select tablename, rowsecurity
    from pg_tables
    where schemaname = 'public'
    order by rowsecurity, tablename;

    Turn it on with alter table public.profiles enable row level security; With RLS on and no policy, nobody can read the table through the API, which is safe but may break your app until you add policies.

  3. Write policies that name the owner

    A typical policy lets people read only their own rows:

    create policy "own rows" on public.orders
      for select to authenticated
      using ((select auth.uid()) = user_id);

    Add separate policies for insert, update and delete, with a with check clause so nobody can write a row in someone else's name. Be suspicious of any policy that says using (true) on a table holding personal or payment data.

  4. Test as a stranger

    On your own project, with only the anon key and no sign-in:

    curl 'https://YOUR-PROJECT.supabase.co/rest/v1/profiles?select=id&limit=1' \
      -H 'apikey: YOUR-ANON-KEY'

    An empty list [] means RLS held. A row means anyone can read that table. Repeat for every table that holds customers, orders, messages or payments.

  5. Check the side doors

    Views ignore RLS unless created with security_invoker = true. Functions marked security definer run with full rights. Storage buckets have their own policies on storage.objects. Check all three.

  6. Keep the service key on the server

    The service_role key (or a new-style sb_secret_… key) skips RLS entirely. It must never appear in browser code or in a NEXT_PUBLIC_ or VITE_ variable. If it ever did, rotate it in the dashboard.

What vibeship checks for you

You can do all of the above by hand. If you'd rather start with a list of what's wrong, the vibeship quick check runs from outside, the way a stranger sees your site. The quick check is free and needs no account. It shows your grade and how many problems sit in each area; what each problem is and how to fix it is in the full report.

Checked automatically

  • Finds your Supabase address and anon key in the scripts your site ships
  • Asks Supabase, as a stranger, for the row count of sensitive tables (users, profiles, accounts, customers, orders, payments and similar). It asks for a count only and never reads a row
  • Reports whether your table names can be listed by anyone
  • Flags a service key or other secret shipped to the browser

Deeper, and what we don't check

  • Only checks well-known table names; a sensitive table called something else is not tested
  • Does not test whether one signed-in user can read another's rows: the deep test with a subscription signs in and tries that
  • Does not read your policies or SQL; with a subscription, the code audit reads your repository

Questions people ask

Is the Supabase anon key secret?

No. It is designed to be in your website, like the newer sb_publishable_ keys. It identifies your project; Row Level Security decides what it may do. The service_role and sb_secret_ keys are the secret ones.

Does the service role key bypass RLS?

Yes, completely. That is why it belongs only on a server or in an edge function, never in the browser.

If RLS is on, am I safe?

Only if the policies are right. RLS with a policy of using (true) for everyone is the same as no RLS. Test as a stranger and as a second user.

Does RLS slow my queries down?

A little, on large tables. Index the columns your policies compare (such as user_id) and wrap auth.uid() in a select as in the example, which Supabase recommends for speed.

Best effort, not a guarantee: Our scans are best effort: they can miss a weakness or flag one that isn't there. This is advice, not a guarantee, and it doesn't replace a security firm. Your site's safety stays your responsibility. Read the terms.

Related guides