New
Apps 608Makers 608This week 608
Promote your app−30%
4views in
the last 30 days

Supabase RLS audit

SQL script that audits Supabase row-level security policies

Built with Claude Code

by tori-tic · added Oct 29, 2026
no ratings0 comments
Open app Code

One read-only SQL file that finds the row-level-security holes in a Supabase project. Every check is tested against a real PostgreSQL, both ways.

Paste supabase-rls-audit.sql into your Supabase SQL editor and run it. It reads your database's catalog, never your rows, and returns what is wrong, worst first, each finding with a plain-language explanation and a starting-point fix. It changes nothing, and it even runs inside a read-only transaction.

No install, no account access, no keys shared. You run it yourself, inside your own dashboard.

What it finds

Severity Check Why it matters
CRITICAL / MEDIUM RLS disabled on a public table When the API roles hold grants on the table, anyone with your public key can read and write every row. MEDIUM when neither API role holds any privilege on it yet: closed today, open to everyone after the first grant.
CRITICAL / HIGH Insert policy checks nothing (WITH CHECK (true)) A user can insert rows carrying another user's id. CRITICAL when the policy has no TO clause, because then signed-out visitors can do it too.
HIGH RLS on, zero policies PostgreSQL denies everything: reads return nothing and inserts fail with 42501.
HIGH API role has no grant A policy lets anon or authenticated in, but that role holds no privilege on the table, so the app gets 42501 permission denied for table and the policy never runs. Supabase no longer grants new public tables to the API roles automatically (new projects since May 30, 2026, existing projects from October 30, 2026). The fix is the GRANT.
HIGH / MEDIUM Any row open to UPDATE or DELETE (USING (true)) HIGH when other users' rows are also readable, because a filtered UPDATE or DELETE only reaches rows the user can read.
HIGH View skips RLS A view runs with its creator's rights unless security_invoker is on. With no filter by the signed-in user, it returns rows RLS would hide.
HIGH View writes skip RLS A view that filters by the signed-in user is safe to read, but if it can be written through, the writes skip RLS: a user can insert rows as someone else or move their own rows to another user.
MEDIUM Update policy checks nothing A user can write any values into rows they may update. On a readable table they can hand a row to someone else.
MEDIUM Readable by everyone Fine for genuinely public data, a leak for private data.
INFO Insert policy grants nothing An INSERT policy with no WITH CHECK allows no inserts at all, a common cause of 42501.

What it deliberately does not flag

  • An UPDATE policy with USING and no WITH CHECK. Many guides call this a hole. It is not: PostgreSQL reuses USING as the check (CREATE POLICY), and the tests below prove a user still cannot hand their row to someone else.
  • The anon role's default table grants. Row level security still decides what gets through; the tests prove a signed-out insert is refused.
  • A view that filters by the signed-in user and cannot be written through, or has a check option. Reading through it is limited to the user's rows, and the tests prove it. The danger in such a view is writes, so it is reported only when writes are possible.

Sample output

From the test suite's fixtures, worst first (the finding and fix columns are omitted here):

severity | object                               | check
CRITICAL | public.rls_off                       | RLS disabled
CRITICAL | public.insert_check_true_public      | Insert policy checks nothing
HIGH     | public.insert_check_true             | Insert policy checks nothing
HIGH     | public.no_policies                   | RLS on, zero policies
HIGH     | public.delete_using_true_public_read | Any row open to DELETE
HIGH     | public.notes_mine                    | View writes skip RLS
HIGH     | public.notes_view                    | View skips RLS
MEDIUM   | public.update_check_true             | Update policy checks nothing
INFO     | public.insert_no_check               | Insert policy grants nothing

Tested, both ways

tests/test_rls_audit.py builds a Supabase-shaped database in a throwaway PostgreSQL (the anon, authenticated and service_role roles, an auth.uid() that reads the JWT subject, and Supabase's default grants), then:

  • runs the audit against tables whose policies are known safe, which must produce no finding, and known dangerous, which must produce exactly the right one;
  • proves each finding's claim by acting as a signed-in user, for example that an insert policy whose check is true really lets user A write a row as user B, that a view without security_invoker really shows A a row RLS hides, and that a view which filters by the signed-in user still lets A write a row as B;
  • checks that the audit runs inside a read-only transaction and that every fix it prints actually executes.
pip install pgserver
python tests/test_rls_audit.py

pgserver ships real PostgreSQL binaries and runs a private server in a temporary folder that is deleted afterwards. Windows wheels exist up to Python 3.12.

Use it from an AI coding agent

skills/supabase-rls-audit/SKILL.md is an agent skill: the agent runs the audit with you and explains each finding in the context of your app.

In Claude Code, install it as a plugin:

/plugin marketplace add Tori-TIC/supabase-rls-audit
/plugin install supabase-rls-audit@supabase-rls-audit

For any other agent, copy the skills/supabase-rls-audit folder into its skills directory.

Seeing an error right now?

The fixes, done for you

The full security pack adds a tested fix recipe for every finding and for the three RLS errors people hit most, plus an agent skill that writes the fixes for your exact tables. The audit itself is, and stays, free.

More from TIC

Free guides on running a small online business, with sources and dates, are at tori-tic.github.io. The 42501 and 42P17 write-ups above are on ticassociation.com.

What it does not do

It catches the failures that keep recurring in AI-built apps. It does not cover every possible misconfiguration (policies built on functions, conditions that are always true in a less obvious way, storage bucket rules), and it is not a replacement for a real security review of a high-stakes app.

License

MIT. Made by TIC Association.

Description taken from the repository README.

Ratings

–
0 ratings
5 0
4 0
3 0
2 0
1 0

Rate this app

Sign in to rate

Comments 0

Sign in to comment

No comments yet.

Related apps

#supabase · #security · #audit