Audit your Supabase in one prompt
Paste this into Claude Code, Cursor, or any agent connected to your project. It runs five read-only checks against your database and tells you which tables are exposed, which policies let everyone through, and which storage buckets are public. No signup, no email.
You are auditing the Row Level Security configuration of my Supabase project.
STEP 1 — Run this query exactly as written. Do not modify it, and do not
substitute your own queries. It reads only Postgres catalogue views
(pg_tables, pg_policies, storage.buckets): it cannot read a single row of my
application data, and it changes nothing.
with findings as (
select 1 as rank, 'CRITICAL' as severity,
'Table has no Row Level Security - readable by anyone with the anon key' as finding,
tablename as object
from pg_tables
where schemaname = 'public' and not rowsecurity
union all
select 1, 'CRITICAL',
'Policy grants read access to everyone (USING true)',
tablename || ' -> ' || policyname
from pg_policies
where schemaname = 'public' and qual = 'true'
union all
select 2, 'HIGH',
'Policy accepts any new row (WITH CHECK true) - records can be reassigned',
tablename || ' -> ' || policyname
from pg_policies
where schemaname = 'public' and with_check = 'true'
union all
select 2, 'HIGH',
'Storage bucket is public - any object URL downloads without auth',
name
from storage.buckets
where public
union all
select 3, 'REVIEW',
'RLS enabled but no policy - table returns nothing to my own app',
t.tablename
from pg_tables t
left join pg_policies p
on p.schemaname = t.schemaname and p.tablename = t.tablename
where t.schemaname = 'public' and t.rowsecurity and p.policyname is null
)
select severity, object, finding from findings order by rank, object;
STEP 2 — Report the results as a table, most severe first, naming the exact
table, policy or bucket. If the query returns no rows, say so plainly instead
of looking for something else to report.
STEP 3 — For each finding, state in one sentence what someone holding my
public anon key could actually do with it.
STEP 4 — Describe the fix for each finding in words. Do NOT run, apply, or
offer to run any statement that modifies my database — no ALTER, no CREATE
POLICY, no DROP, no migration. I will make the changes myself.
STEP 5 — Finally, list which of these findings could silently come back after
a future migration or a future prompt, and explain why a one-time audit cannot
catch that.What it checks
- Tables with no Row Level Security — readable by anyone holding your anon key, which is published in your frontend bundle by design.
- Policies that evaluate to
true— switched on, attached, and returning every row to everybody. These pass any audit that only asks whether RLS is enabled. - Policies with
WITH CHECK (true)— a user can reassign a record they own to somebody else. Usually added to silence an error rather than to grant anything. - Public storage buckets — correct for avatars, wrong for the invoices and documents that end up in the same place because public buckets are where uploads work first time.
- Tables with RLS on and no policy — not a breach, but the reason a feature quietly returns nothing, and the usual prelude to somebody disabling RLS to fix it.
No agent connected?
Copy the with findings as (…) query out of the prompt and paste it straight into the Supabase SQL editor. You get the same table of findings without the explanations — the SQL is the audit, the prompt is only the part that reads it back to you.