Check what your Supabase project shows the world

The anon key is supposed to be public. The protection is Row Level Security — and the one key that bypasses it must never reach the browser. We check both from the outside, the way an attacker would, without touching your data.

Free, no sign-up. The basic check makes only the requests an ordinary browser would.

See a full example report

What we check

Check it yourself in five minutes

Everything we check from the outside you can check from your own dashboard and terminal. Do it on your own project only.

  1. List tables without Row Level Security

    Supabase dashboard → SQL Editor. Any public table with rowsecurity = false is readable by the anon key if the default grants are in place. The Security Advisor (Advisors → Security) shows the same list.

    select tablename, rowsecurity
    from pg_tables
    where schemaname = 'public'
    order by rowsecurity, tablename;
  2. Try it as a stranger

    Use the anon key from your site — the same one every visitor has. If this returns rows, so does it for anyone.

    curl 'https://<project>.supabase.co/rest/v1/<table>?select=*&limit=1' \
      -H "apikey: <anon key>" \
      -H "Authorization: Bearer <anon key>"
  3. Make sure the secret key never reached the browser

    On your live site open DevTools, search all loaded files (Cmd/Ctrl + Option/Alt + F) for service_role and sb_secret_. Any hit means: rotate the key in Project Settings → API, then move that code to an Edge Function.

  4. Turn RLS on and add a policy

    Enabling RLS without a policy blocks everything — add one that matches how the table is used. For a table of user profiles:

    alter table public.profiles enable row level security;
    
    create policy "read own profile"
    on public.profiles for select
    using (auth.uid() = id);

A fix your AI can apply

The report’s prompt names the tables and the exact problem, and asks your AI to enable RLS with policies that match how the app uses each table.

Fix these issues on app.example.com.

1. The table "profiles" returns 1,240 rows to the anon key.
   Enable Row Level Security on it and add a policy so users can select only their own row (auth.uid() = id).

2. The table "orders" returns 87 rows to the anon key.
   Enable RLS; allow select only to the order's owner.

When done, re-check: https://scanyoursite.app/en?check=app.example.com

A new table is a new risk

Every migration can add a table without a policy. With Pro the table check runs on every scheduled scan, and you hear about a newly open table the same day.

See plans

Questions

Why do I need to verify my domain for the table check?

Querying a database goes beyond what a browser does on a page, so we only do it for the owner. Verification takes a DNS record, a file or a meta tag.

Do you store my data?

No. We count rows with a HEAD request and keep only the number and the table name.

Is the anon key a leak?

No. It is public by design. We report it as a note, not a problem.

For vibe coders

Paste your URL. Get the list in about a minute.

Every finding comes with what it means for you and how to fix it — or a prompt your AI coding tool can apply.

Free, no sign-up. The basic check makes only the requests an ordinary browser would.