Guides
Supabase access-rule mistakes that pass security scans and still leak data, with the fix for each.
If you built your app with an AI assistant, your tables and your row level security policies were probably written in the same conversation. That is the problem: the policy looks reasonable, the Supabase Security Advisor says nothing, and the data is still readable by a signed-out visitor with curl. These guides walk through the specific mistakes we keep finding in real projects, one at a time, with a query you can run to check your own project and the exact policy change that fixes it.
What these guides cover
- Policies that allow when they should deny. A rule meant to protect rows is written as a
USINGcondition a signed-out request still satisfies, so it hands data out instead of holding it back. - Nulls treated as "no match".
auth.uid(), a role, or a tenant id isnullfor anonymous requests, and the policy quietly evaluates to true instead of false. - Readable storage buckets. Private files stay world-listable because the bucket is public or the storage policy is wider than the table policy.
- Role confusion. "Signed in" is treated as "allowed", so any user who signs up can read every other user's rows.
- Client-trusted fields. A writable
role,plan, oris_admincolumn that a user can set on themselves.
The guides
-
Lovable's security scan passed. Here are 5 ways your Supabase data can still be exposed
Null-user bypasses, public reads of personal data, "signed in" counted as "allowed", users who make themselves admin, and private buckets anyone can list.
-
auth.uid() is null: the RLS policy that lets signed-out visitors read everythingWhy it looks safe, why the Supabase Security Advisor misses it, a one-query check and the fix.
Why a passing scan is not proof
A scanner checks that row level security is on for your tables. It does not read your policies and decide whether they describe what you meant. A table with row level security enabled and a policy of true passes every scanner and leaks every row. That gap between "RLS is enabled" and "the policy actually restricts access" is what these guides are about, and it is also what RLS Check looks for by running real requests against your project instead of reading its settings.
How to check your own project
Read the guide that matches your setup, or run the check first and come back to the guide for whatever it flags. The check is free, runs read-only queries and live requests, and gives you a short report of which rows a signed-out visitor can actually reach, so you can fix the ones that matter before a stranger finds them.