One SQL file. Paste it into the Supabase SQL Editor, hit Run, get a list of the
things that are about to bite you — worst first.
No install, no npm package, no connection string handed to a stranger, no
account anywhere. It only SELECTs from system catalogs: it reads none of your
table data, writes nothing, and sends nothing anywhere. It is one file so that
you can read it before you run it.
curl -O https://raw.githubusercontent.com/Concepto505/supabase-audit/main/audit.sql
What the output looks like
Illustrative — table names invented, shape is real:
Nothing came back? Then these eleven failure modes are not present. That is a
useful answer too.
Two of these deserve a note
#4 is the one that surprises people. In Postgres, a newly created function
is executable by PUBLIC unless you say otherwise. On Supabase that means the
anon key can call it. The REVOKE has to live in the same migration that
creates the function, or there is a window where it is open.
#6 is not automatically a bug. A view without security_invoker runs with
its owner's rights, which is exactly right when the view already filters by
auth.uid() itself. Read the definition before you change it. Tools that flag
every such view as an issue are generating noise.
Heuristics, stated plainly
Checks 9 and 10 are heuristics. #9 matches a policy expression that mentions its
own table name — confirm by reading the policy. #10 matches only the leading
index column, so an unusual composite index can produce a false positive. Both
are deliberately tuned to over-report rather than miss something.
Tested against Postgres 17 / Supabase. Requires Postgres 15+ for the
security_invoker check; everything else works on 12+.
MIT. Take it, fork it, put it in your CI.
Built by David Borrás, who fixes these for a
living when reading the list is not what you wanted to do tonight.