Supabase table readable without login
Your Supabase anon key is public. Whether it can read your users table depends only on Row Level Security. This check sends the same request a curious visitor could, and tells you which tables answer.
Verified Runs after you verify your domain. Verification is free on every plan.
What it is
A frontend that uses Supabase talks to the Data API at https://<project>.supabase.co/rest/v1/. Each request carries the anon key and, after sign-in, the user’s token. Postgres then applies RLS policies to decide which rows the request can see. If RLS is disabled on an exposed table, or a policy allows the anon role to read everything, the table is open to anyone who copies the key from your JavaScript.
What can happen
Anyone can run one curl command and download the table: emails, names, phone numbers, orders, private messages, whatever lives there. No password cracking, no exploit. Because it looks like normal API traffic, you will probably not notice it in your logs either. If the policy also allows writes, they can change or delete data.
How Shypset checks it
This is a Verified check. Sending requests to your backend goes beyond what a browser on your homepage does, so we run it only after you prove you own the domain. Here is exactly what it does:
- Finds your Supabase URL and anon or publishable key in the page and bundle.
- Collects table names your bundle references, plus those in the API schema if it is exposed. Up to 25 tables; we do not guess names.
- Sends
GET /rest/v1/<table>?select=*&limit=1with the anon key, three at a time, with short timeouts. - Keeps the HTTP status, whether a row came back, the column count and up to 10 column names. The row itself is discarded and never stored.
- Raises severity to critical when column names look like personal or secret data.
It uses only GET and only the public key. A service_role key is never used for probing. If the Supabase project looks like it belongs to a third-party service rather than to you, we report that it was found but not checked.
How to fix it
Enable RLS on the table with alter table public.<name> enable row level security; and add policies for the access you want, typically using (auth.uid() = user_id) for the authenticated role. Remove any using (true) policy for anon unless the data is meant to be public, like a pricing table, in which case you can ignore the finding. Then rescan: the anon key should no longer return rows.
Example finding
A typical finding and the fix prompt that comes with it.
orders is readable without loginEvidence
Table: orders Request: GET /rest/v1/orders?select=*&limit=1 with the anon key HTTP status: 200 Rows returned: yes Column count: 9 Columns (first 5): id, user_id, email, address, total
Fix prompt
The Supabase table orders can be read with the anon key. Write a migration that enables RLS on public.orders, adds a select policy for the authenticated role using (auth.uid() = user_id), and no policy for anon. Check all other tables in the public schema the same way and list any that still allow anonymous reads.
Questions
- Why do I need to verify my domain for this check?
- The probe queries your backend directly. We only do that for sites whose owner has confirmed it, and verification is free on every plan.
- Does this check find policies that leak data between signed-in users?
- No. That needs a logged-in test, and Shypset does not log in. It finds tables open to anonymous visitors.
Check your Supabase tables
Scan your app from the home page, then verify the domain to run the table probe.
Scan your app