Supabase RLS checker

Which of your Supabase tables can anyone read or write?

Your anon key ships in the browser. That is fine only if row-level security is on for every table the API serves, and every policy is narrower than true. Paste the GitHub repo of a Supabase, Lovable, Bolt or v0 app and Wyro reads the migrations and the code to show you where it isn't.

Free for public repositories. No account and nothing installed. Lovable, Bolt and v0 projects work once they are synced to GitHub.

What to check, and how

  1. Row-level security is on for every table in an exposed schemaWyro checks this

    A table in public with RLS off is readable and writable by anyone holding the anon key, which is everyone who has opened your site. Run this in the SQL editor:

    select schemaname, tablename
    from pg_tables
    where schemaname = 'public' and rowsecurity = false;

    Wyro reports the same thing from your migrations as rls-disabled.

  2. No policy lets anyone writeWyro checks this

    RLS on with using (true) or with check (true) on an insert or update policy is the same as RLS off for writes. List them:

    select tablename, policyname, cmd, roles, qual, with_check
    from pg_policies
    where schemaname = 'public'
      and (qual = 'true' or with_check = 'true');

    Wyro flags these as rls-open-write.

  3. Know which browser queries rely on RLS aloneWyro checks this

    Every supabase.from("table") call in client code is a public endpoint at /rest/v1/table. Wyro lists each one and the table it reaches, and marks the ones where the only thing between a stranger and the data is a policy (rls-only), so you know exactly which policies to read twice.

  4. The service-role key never reaches the browser

    The service-role key bypasses RLS entirely. Search your client bundle and repo for service_role and for any env var without a server-only prefix that holds it. If it ever shipped, rotate it in the dashboard; deleting the commit does not un-leak it.

  5. Edge Functions check who is callingWyro checks this

    verify_jwt = true accepts the public anon key, because the anon key is a valid JWT. A function that then uses the service-role client and trusts IDs from the request body lets anyone act on anyone's rows. Read the caller from the JWT, or verify a webhook secret, before touching data.

  6. Storage buckets are private unless they must be public

    A public bucket serves every object to anyone with the URL. Keep uploads in private buckets and hand out signed URLs.

Keep it that way

A check run once goes stale the next time an agent adds a route. Sign in, press Watch this repo on its report, and Wyro emails you the day a push adds a new finding. Free.

Questions

Is this an official Supabase tool?

No. Supabase has a Security Advisor in the dashboard that checks the live database. Wyro reads your repository instead, so it also sees which code paths reach which tables, and it runs on a pull request before anything is deployed.

Does it need my database password or keys?

No. It reads the public GitHub repository: the SQL migrations under supabase/migrations and the code that calls supabase-js. Nothing connects to your project.

My app was built with Lovable or Bolt. Will it work?

Yes, once the project is synced to GitHub. Paste the repository URL. Browser calls become /rest/v1 endpoints and Edge Functions become /functions/v1 endpoints in the report.

Is it really free?

Checking public repositories is free and unmetered. There is no model in the check, so it costs almost nothing to run. Private repositories and CI enforcement are paid.

wyro.in/supabase-rls-checker