TIC Association
Supabase security

Find the RLS holes before your users do.

The most common way an AI-built app leaks data is not a crash. It is quiet: row level security switched on while the policies do nothing, or switched off on a table nobody remembered. This one SQL file finds those holes in about a minute.

Free. Read-only. No install, no account access, no keys shared.

what you run

One SQL file. You paste it and run it. It reads, it never writes.

You open your Supabase SQL editor, paste the file, and run it. It reads your database's own catalog and hands back a prioritized list of the security holes that matter, each with a plain-language explanation and a copy-paste fix. It never reads your rows, changes a setting, or phones home. Read the code and see for yourself.

severity | object | finding CRITICAL | public.profiles | RLS is OFF, table is world-readable and writable CRITICAL | public.messages | anon role holds a direct write grant HIGH | public.orders | RLS on, zero policies (silently blocks or exposes) HIGH | public.invoices | write policy missing WITH CHECK (write-as-anyone) OK | public.audit_log | RLS on, policies scoped to auth.uid()
what it checks

The five holes that leak real data.

Critical

RLS switched off

The number one leak. A table anyone can read or write, usually because it was created after row security was set up and never got locked down.

High

RLS on, zero policies

Row security is on but no policy exists, so the table silently blocks everything or exposes everything depending on the grant. This is the usual cause of the 42501 error.

High

Write policy with no WITH CHECK

A policy that checks who can write but not what they write, which lets a user insert or update rows as if they were someone else.

High

Policies open to everyone

A policy that looks secure but resolves to true for all, so it protects nothing while appearing to.

Critical

anon holds a direct grant

The anonymous role granted write access straight on a table, bypassing your policies entirely.

why this keeps happening

The tables an AI builder makes for you do not get row security by default.

This is the part that catches people, and it is documented behaviour rather than a bug. Supabase turns row level security on automatically for a table you create in the dashboard Table Editor. A table created in raw SQL does not get it. As Supabase's own guide puts it: "RLS is enabled by default on tables created with the Table Editor in the dashboard. If you create one in raw SQL or with the SQL editor, remember to enable RLS yourself."

AI builders write raw SQL. Lovable, Bolt, Replit and the rest create your schema through the SQL editor, not by hand in the Table Editor, so the one path that switches row security on for you is the path your app never took. That single detail explains most of what the auditor finds on an AI-built project.

The second most common finding is subtler, because the table looks protected. A policy can control what a user is allowed to read while placing no constraint at all on what they are allowed to write. PostgreSQL is explicit about the split:

"Existing table rows are checked against the expression specified in USING, while new rows that would be created via INSERT or UPDATE are checked against the expression specified in WITH CHECK." PostgreSQL documentation, CREATE POLICY

So a policy written with USING and no WITH CHECK passes every read test you can think of and still lets one user write rows as another. It is the reason an app can look correct in manual testing and be wrong in production.

And when row security is on with no policy behind it, PostgreSQL refuses the query with error code 42501, which its error appendix defines as insufficient_privilege. That error is not the problem. It is the symptom of a table whose policies were never written, and it is the one people paste into a search box at two in the morning.

how to check

Three steps, about a minute, nothing shared.

To check a Supabase project for row level security holes: open the SQL editor in your own dashboard, run a read-only query against the Postgres catalog tables that store your policies, and read off which tables have row security disabled, enabled with no policy behind it, or a write policy with no WITH CHECK clause. You do not need to install anything or give anyone access to do it.

1

Open your own SQL editor

In your Supabase dashboard, open the SQL editor. Everything happens inside your project. Nothing is pasted into anyone else's form.

2

Paste the auditor and run it

It queries the catalog only: which tables have row security on, which policies exist, what each policy actually resolves to, and which grants the anonymous role holds.

3

Read the findings worst first

You get a severity-ordered list, each row naming the table, the specific hole, and the SQL that closes it. Fix the criticals before anything else ships.

why this format

Safe by design, so you never have to trust us with anything.

Most free RLS checkers are websites that ask you to paste your project URL and your anon key into someone else's form. This one never asks. It is a SQL file you run inside your own dashboard, and it ships the fixes, not just the findings.

No install

It is plain SQL. There is nothing to run on your machine and nothing to add to your project.

No account access

You never share your database password, your service key, or your project. You run it yourself, inside your own dashboard.

Read-only

It reads system catalogs only. It does not read your rows, write anything, or change a setting.

Works everywhere

Any Supabase project, nothing to configure. It ships with fix recipes and a Claude Code skill that writes the fixes for your exact tables.

start here

Run your preflight.

Download the auditor, paste it into your Supabase SQL editor, and read your findings. It catches the common, repeated failure patterns fast. It is not a full penetration test, so a high-stakes app still deserves a real review. Use it as your pre-launch preflight.

Download the free auditor

The free download is the read-only auditor SQL plus a plain-language README.

Want the fixes handed to you? The full security pack adds copy-paste fix recipes for every finding class and a Claude Code skill that writes the fixes for your exact tables.

if it finds something you cannot fix

We fix broken AI-built apps for a living. RLS is what we fix most.

If the auditor flags a hole and you would rather someone just fix it, that is our work. Send us the error and we diagnose it free. You pay only after the fix is verified working, and you own the clean code.

Get a free diagnosis

questions

Straight answers.

Is it safe to run on my production database?
Yes. It reads system catalogs only. It does not touch your data, change any setting, or send anything anywhere. You can read the whole file before you run it.
Do I have to share my keys or give access?
No. You paste and run it yourself inside your own Supabase SQL editor. You never share a password, a service key, or your project with anyone.
What if it finds a problem I do not know how to fix?
Each finding ships with a copy-paste fix recipe. If you would rather have it done for you, we fix broken AI-built apps at rescue.ticassociation.com, free diagnosis, pay only after it works.
Is this a full security audit?
No. It catches the common, high-frequency RLS mistakes that leak data in AI-built apps. Treat it as a fast preflight, not a replacement for a full review on a high-stakes app.
Why does an AI-built Supabase app so often have RLS switched off?
Because of which path created the table. Supabase enables row level security automatically for tables created in the dashboard Table Editor, but not for tables created in raw SQL or the SQL editor, where you have to enable it yourself. AI builders such as Lovable, Bolt and Replit generate your schema in SQL, so the one path that turns row security on for you is the path your app never took.
What does Postgres error 42501 mean in Supabase?
42501 is the PostgreSQL error code for insufficient_privilege. In a Supabase app it usually means row level security is enabled on the table but no policy grants the current role access, so the query is refused. The error is the symptom; the missing policy is the cause.

Close the holes before someone finds them.

Download the free auditor
© 2026 TIC Association Privacy · Terms hello@ticassociation.com