Supabase RLS checker

Paste your app URL. We find the Supabase keys your frontend ships, flag a leaked service_role key instantly, and tell you exactly what to verify in Row Level Security.

Passive check: we only fetch public pages and scripts. Only scan sites you own or are authorized to test.

Why the anon key is not the problem (and RLS is)

Every Supabase app built with Lovable, Bolt, v0 or Cursor ships a project URL and an anon key to the browser. That is by design: the anon key is a public JWT with the anon role, and the Supabase client libraries need it to talk to your database's REST API (PostgREST). Seeing it in DevTools is not a leak.

What it does mean is that one thing now stands between the internet and every row of your data: Row Level Security (RLS). Anyone can copy your anon key and call https://<project>.supabase.co/rest/v1/<table> directly, outside your app, with no UI and none of your frontend checks. If a table in the public schema has RLS turned off, or has a policy like using (true), that request returns the whole table. In our scan of 99 launched vibe-coded apps, 37% exposed a Supabase anon key, so for more than a third of them, RLS was the entire security model.

What this checker does

  • Finds Supabase config in your HTML and up to 25 same-site JavaScript bundles, and decodes the JWT to confirm its role.
  • Flags a service_role key as critical. The service_role key bypasses RLS completely. If it is in your bundle, anyone can read, edit and delete everything. Rotate it immediately.
  • Scans for other secrets (OpenAI, Stripe live, AWS, GitHub and more) in the same pass.
  • Runs deeper checks only on sites you own. Testing whether your anon key can list your API schema means touching your database, so we only do it after you verify ownership with a meta tag, file or DNS record.

How to check RLS yourself in five minutes

  1. Open the Supabase dashboard → Table Editor. Every table without RLS shows an "RLS disabled" or "Unrestricted" badge. There should be none in public.
  2. Or run this in the SQL editor: select tablename, rowsecurity from pg_tables where schemaname = 'public'; Any row with rowsecurity = false needs fixing.
  3. Enable it: alter table public.profiles enable row level security; With RLS on and no policies, the anon role gets nothing, which is the safe default.
  4. Add narrow policies, for example create policy "own rows" on public.profiles for select using (auth.uid() = user_id); Write separate policies for insert, update and delete, and use with check on writes so users can't insert rows for someone else.
  5. Search your policies for using (true). It is fine for genuinely public data like a blog's published posts, and a disaster on users, orders or messages.
  6. Test as an outsider: call the REST endpoint with only the anon key and no user session, and confirm you get an empty array or a 401.

Common RLS mistakes in vibe-coded apps

Policies that check the wrong column. AI tools sometimes generate auth.uid() = id on a table where id is the row id, not the owner. The policy looks right and lets nobody (or the wrong person) in. Trusting the client for roles. A policy that reads an is_admin column the user can update themselves is not a policy. Keep role data in a table users can't write, or in JWT custom claims. Storage buckets. Supabase Storage has its own policies on storage.objects; a public bucket full of user uploads is a common leak. Views and functions. Views run with the owner's permissions by default and can bypass RLS; use security_invoker = true on Postgres 15+. security definer functions exposed via RPC need the same care.

The fix prompt

If you build with an AI editor, paste this: "Audit my Supabase project. For every table in the public schema, enable Row Level Security and write policies so users can only select, insert, update and delete their own rows (auth.uid() = user_id). List any table with RLS disabled or a policy using (true), and check storage bucket policies too." Then re-run this checker and the outsider test above.

Check everything in one scan.

Leaked keys, database exposure, headers, SEO, performance and broken links, with a copy-paste fix prompt for Cursor or Lovable on every issue. Free to run.

Run the full free scan →

FAQ

Is it safe to expose the Supabase anon key?

Yes, as long as Row Level Security is enabled with correct policies on every table in your exposed schemas. The anon key is designed to be public; RLS is what protects your data.

What happens if my service_role key leaks?

The service_role key bypasses Row Level Security entirely, so anyone who has it can read, modify and delete all data. Rotate it in the Supabase dashboard right away and only use it in server-side code.

Can this tool tell if RLS is enabled?

The free passive check finds your Supabase keys and leaked secrets without touching your database. Schema exposure checks run only after you verify you own the site. To confirm RLS directly, query pg_tables for rowsecurity = false in the SQL editor.

Does ShipSniffer read my data?

No. The passive check only downloads the public pages and JavaScript any visitor would get. Even verified deep checks only test whether data is publicly reachable; we never store table contents.

More free tools