Supabase security scanner
Supabase is secure when it is configured, and open when it is not. The gap between the two is Row Level Security and where you keep your keys. This page checks both on your live app, whatever built it.
Scan your Supabase app
What it means
Your database tables can be read by anyone, not just logged-in users. Someone could open your app's data — customer emails, orders, private records — without ever creating an account.
Why AI tools cause it
Supabase only protects a table once you turn on Row Level Security (RLS) and write access rules for it. AI tools frequently build a working app without doing that, so the tables are wide open by default.
How xlogs checks it
xlogs finds your public Supabase URL and anon key in your app (the same ones your frontend uses), asks the database as an anonymous user which tables it can read, and flags any that return real rows. Read-only: it never writes or deletes.
The two Supabase mistakes worth checking first
First, tables with Row Level Security off. The public anon key your frontend ships is meant to be public, but without table policies it lets anyone read your data. Second, a service_role key that leaked into the frontend. That key bypasses RLS entirely, so it is the most dangerous thing you can expose.
The scan checks both. It tests your tables with an anonymous read, and it scans your shipped JavaScript for a leaked service key. It never flags the public anon key, because that one is supposed to be there.
How to fix it
The goal: Row Level Security is enabled on every table, with policies so a table only returns rows to users allowed to see them; no table returns private data to an anonymous request.
- Enable Row Level Security (RLS) on every table, especially the affected spot
- Add a policy per table so only authenticated users can read/write their own rows (keep intentionally-public tables public on purpose)
- Re-check that an anonymous request no longer returns private rows
In my app (the spot the scan shows): anyone can read this database table. Please make this true: Row Level Security is enabled on every table, with policies so a table only returns rows to users allowed to see them; no table returns private data to an anonymous request. Steps: Enable Row Level Security (RLS) on every table, especially the spot the scan shows; Add a policy per table so only authenticated users can read/write their own rows (keep intentionally-public tables public on purpose); Re-check that an anonymous request no longer returns private rows. Then tell me exactly what you changed, and do not print any secret values back to me.
Then verify: After you deploy the policies, xlogs repeats the same anonymous read test and confirms the table no longer returns data without a login.
Full step-by-step fix guide, with a copy-paste block for each AI tool →
Common questions
Is Supabase secure out of the box?
No. Supabase gives you the tools to be secure, but a new table starts without policies. You have to turn on Row Level Security and write policies. Until then, the table is readable by anyone with the public key.
Which Supabase key is safe to ship in the browser?
The anon key is public and safe to ship in the browser; it obeys your RLS policies. The service_role key ignores RLS and can do anything, so it must stay server-side only. If a service key is in your frontend, treat it as an emergency and rotate it.
