Supabase Security Advisor vs xlogs
Supabase ships a Security Advisor in its own dashboard, and it is good. It is not competing with xlogs, because the two answer different questions. The Advisor reviews your configuration from inside your project. xlogs tests your live app from outside, as a stranger with no login. You want both.
Test it from the outside
What it means
Anyone can read this table without logging in. That can be deliberate, such as reference data or a public directory, or a missing access policy; only you can say which. xlogs read one row's column names and kept none of its values.
Why AI tools cause it
Supabase only limits who can read a table once you turn on Row Level Security (RLS) and write access rules for it. An AI tool can build a working app without doing that, and a table without RLS, or with a policy that lets everyone read, answers anonymous requests.
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 for its table list, reads one row from each listed table as an anonymous user, and flags any that return rows. Hosted Supabase refuses that list to public keys, so on a hosted project the result says the tables could not be checked. Read-only: it never writes or deletes.
Inside view versus outside view
The Supabase Security Advisor runs inside your dashboard with project access. It reads your configuration and reports issues such as RLS disabled or missing policies, overly permissive rules, exposed auth tables, privilege escalation through SECURITY DEFINER functions, and GraphQL introspection exposure. Several of those are things xlogs cannot see at all, because they are only visible from inside the project.
xlogs never logs in. It finds the public Supabase URL and anon key your app already ships to every browser, then asks your tables for data as an anonymous stranger would. If rows come back, that is not a configuration opinion, it is a demonstration.
Both are worth running. The Advisor catches more classes of problem inside the database. xlogs shows what an anonymous request actually got back, including cases where the app ships a key or setting that the database config alone would not reveal.
| xlogs | Supabase Security Advisor | |
|---|---|---|
| Where it runs | From outside, on your live URL | Inside the Supabase dashboard |
| Access needed | None. No login, no project access | Your Supabase project |
| How it judges RLS | Sends an anonymous read and reports what came back | Reviews your policies and configuration |
| SECURITY DEFINER, GraphQL introspection, auth tables | Not visible from outside | Yes, and this is a real advantage |
| Secrets in your shipped JavaScript | Yes | Out of scope |
| Works after you leave Supabase's dashboard | Yes, on any host | Supabase projects only |
| Price | Free | Included with Supabase |
How to fix it
The goal: Row Level Security is enabled on every table, and each table returns rows only to the users it is meant for: a private table answers no anonymous request, and a table that is public on purpose has a read policy that says so.
- Decide whether the affected spot is meant to be readable without a login
- If it is not, enable Row Level Security (RLS) on the affected spot and add a policy so only the users allowed to see a row can read it
- If it is, keep it public on purpose, and record that decision so a review does not reopen it
- Do not switch on a restrictive policy for a table your public pages read without a replacement read policy, or those pages stop working
- Re-check that an anonymous request returns what you decided it should
In my app (the spot the scan shows): anyone can read this table; confirm that is deliberate. Please make this true: Row Level Security is enabled on every table, and each table returns rows only to the users it is meant for: a private table answers no anonymous request, and a table that is public on purpose has a read policy that says so. Steps: Decide whether the spot the scan shows is meant to be readable without a login; If it is not, enable Row Level Security (RLS) on the spot the scan shows and add a policy so only the users allowed to see a row can read it; If it is, keep it public on purpose, and record that decision so a review does not reopen it; Do not switch on a restrictive policy for a table your public pages read without a replacement read policy, or those pages stop working; Re-check that an anonymous request returns what you decided it should. Then tell me exactly what you changed, and do not print any secret values back to me or write one into a commit message, a pull request description or a log.
Then verify: After you decide and deploy, xlogs repeats the same anonymous read of each table the database lists and reports what comes back: a table you made private should no longer return rows, and one you keep public still will. If the table list is refused, it says the tables could not be checked.
Full step-by-step fix guide, with a copy-paste block for each AI tool →
Common questions
If the Supabase Advisor says I am fine, do I need xlogs?
Yes, because the two can disagree, and that is the point. The Advisor reviews the database's own configuration. xlogs tests what your deployed app actually exposes, which also covers keys shipped in your frontend and settings applied outside the database. A clean Advisor plus a clean anonymous read from outside is a much stronger position than either alone.
Does xlogs need my Supabase credentials?
No. It only uses the public anon key your app already sends to every visitor's browser. There is nothing to connect and no password to hand over.
