Supabase RLS Auditor
Audit Supabase Row Level Security policies for correctness and security: checks for missing RLS, unrestricted USING (true), missing WITH CHECK, anon access leaks, service-role bypasses, and auth.uid() typos that silently lock out all users.
@api/supabase-rls-auditor
Supabase RLS Auditor
Purpose: Audit a Supabase database migration file or SQL containing Row Level Security (RLS) policies for correctness and security. Catches the mistakes that silently either expose all data or lock out all users. Every Supabase table touched by users should pass this audit before going to production.
Invocation
/rls-audit <migration-file-or-sql>
The 8-Point RLS Checklist
Check 1: RLS Enabled on Every Table
Every table that stores user data must have:
ALTER TABLE [table_name] ENABLE ROW LEVEL SECURITY;
Failure: Table has no RLS — all authenticated users can read/write all rows.
Check 2: No Unrestricted USING (true) on Sensitive Tables
-- ❌ BAD — exposes ALL rows to ALL authenticated users
CREATE POLICY "all_read" ON users FOR SELECT USING (true);
-- ✅ GOOD — only user's own rows
CREATE POLICY "own_rows" ON users FOR SELECT USING (auth.uid() = user_id);
Exception: Public tables (e.g., skills with status = 'active') may use USING (true) for SELECT only.
Check 3: INSERT Policies Have WITH CHECK
-- ❌ BAD — INSERT policy with no WITH CHECK
CREATE POLICY "insert_tip" ON tips FOR INSERT TO authenticated USING (true);
-- ✅ GOOD
CREATE POLICY "insert_tip" ON tips FOR INSERT TO authenticated
WITH CHECK (auth.uid() = tipper_id);
Check 4: No Anon Role Access to Private Tables
Policies with TO anon on tables containing user data are dangerous. Flag any policy where:
- Role is
anonor omitted (defaults to all roles including anon) - Table contains PII (email, phone, address) or financial data
Check 5: Service Role Bypasses Are Documented
-- This bypasses ALL RLS — it should be intentional and documented
CREATE POLICY "service_role_all" ON [table]
USING (auth.role() = 'service_role');
Flag: every service-role bypass needs a comment explaining WHY it's needed.
Check 6: auth.uid() Typo Check
Common typo that silently evaluates to NULL = user_id (always false — locks out all users):
-- ❌ BAD TYPOS
USING (auth.uid = user_id) -- missing () → NULL
USING (auth.uid() = userId) -- camelCase column name
USING (auth_uid() = user_id) -- underscore instead of dot
-- ✅ CORRECT
USING (auth.uid() = user_id)
Check 7: Separate Policies per Operation
-- ❌ BAD — FOR ALL lets users UPDATE and DELETE other users' data if USING passes
CREATE POLICY "user_access" ON orders FOR ALL USING (auth.uid() = user_id);
-- ✅ GOOD — explicit per-operation policies
CREATE POLICY "select_own" ON orders FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "insert_own" ON orders FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "update_own" ON orders FOR UPDATE USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
Check 8: Recursive Policy Risk
Policies that query the same table they protect can cause infinite recursion. Flag any policy that contains a subquery on the same table.
Output Format
## RLS Audit: [migration file name]
### Tables Audited: N
---
#### [table_name]
| Check | Status | Notes |
|-------|--------|-------|
| RLS enabled | ✅ / ❌ FAIL | |
| No unrestricted USING | ✅ / ⚠️ REVIEW | |
| INSERT has WITH CHECK | ✅ / ❌ FAIL | |
| No anon leaks | ✅ / ❌ FAIL | |
| Service bypasses documented | ✅ / ❌ FAIL | |
| auth.uid() correct | ✅ / ❌ FAIL | |
| Per-operation policies | ✅ / ⚠️ REVIEW | |
| No recursion risk | ✅ / ❌ FAIL | |
**[table_name] verdict:** PASS / FAIL / NEEDS REVIEW
---
### Overall Audit Result: PASS / FAIL
Critical issues (must fix before production): [N]
Warnings (review before production): [N]
### Fix SQL
[SQL to fix any FAIL items]
Rules
- Check 1 (RLS enabled) failure is always CRITICAL — no exceptions
- Check 2 (USING true) on private tables is always CRITICAL
- Flag any policy targeting
FOR ALL— it's almost always wrong - If a table has no policies at all (but RLS is enabled): that's a lockout — all inserts/selects will fail silently
$20 more to next tier
Created by
Info
Embed
Add this skill card to any webpage.
<iframe src="https://skillslap.com/skill/e95dd9f5-5389-4add-b1af-a6cc5bc4eb68/embed"
width="400" height="200"
style="border:none;border-radius:12px;"
title="SkillSlap Skill: Supabase RLS Auditor">
</iframe>