RLS Policy Audit
π΄ CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED
You MUST write to context files AS YOU GO, not just at the end.
- Write to
.sb-pentest-context.json IMMEDIATELY after each finding
- Log to
.sb-pentest-audit.log BEFORE and AFTER each test
- DO NOT wait until the skill completes to update files
- If the skill crashes or is interrupted, all prior findings must already be saved
This is not optional. Failure to write progressively is a critical error.
This skill tests Row Level Security (RLS) policies for common vulnerabilities and misconfigurations.
When to Use This Skill
- After discovering data exposure in tables
- To verify RLS policies are correctly implemented
- To test for common RLS bypass techniques
- As part of a comprehensive security audit
Prerequisites
- Tables listed
- Anon key available
- Preferably also test with an authenticated user token
Understanding RLS
Row Level Security in Supabase/PostgreSQL:
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users see own posts"
ON posts FOR SELECT
USING (auth.uid() = author_id);
If RLS is enabled but no policies exist, ALL access is blocked.
Common RLS Issues
| Issue |
Description |
Severity |
| RLS Disabled |
Table has no RLS protection |
P0 |
| Missing Policy |
RLS enabled but no SELECT policy |
Variable |
| Overly Permissive |
Policy allows too much access |
P0-P1 |
| Missing Operation |
SELECT policy but no INSERT/UPDATE/DELETE |
P1 |
| USING vs WITH CHECK |
Read allowed but write inconsistent |
P1 |
Test Vectors
The skill tests these common bypass scenarios:
1. Unauthenticated Access
GET /rest/v1/users?select=*
# No Authorization header or with anon key only
2. Cross-User Access
# As user A, try to access user B's data
GET /rest/v1/orders?user_id=eq.[user-b-id]
Authorization: Bearer [user-a-token]
3. Filter Bypass
# Try to bypass filters with OR conditions
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
4. Join Exploitation
# Try to access data through related tables
GET /rest/v1/comments?select=*,posts(*)
5. RPC Bypass
# Check if RPC functions bypass RLS
POST /rest/v1/rpc/get_all_users
Usage
Basic RLS Audit
Audit RLS policies on my Supabase project
Specific Table
Test RLS on the users table
With Authenticated User
Test RLS policies using this user token: eyJ...
Output Format
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
RLS POLICY AUDIT
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Project: abc123def.supabase.co
Tables Audited: 8
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
RLS Status by Table
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1. users
RLS Enabled: β NO
Status: π΄ P0 - NO RLS PROTECTION
All operations allowed without restriction!
Test Results:
βββ Anon SELECT: β Returns all 1,247 rows
βββ Anon INSERT: β Succeeds (tested with rollback)
βββ Anon UPDATE: β Would succeed
βββ Anon DELETE: β Would succeed
Immediate Fix:
```sql
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users see own data"
ON users FOR ALL
USING (auth.uid() = id);
```
2. posts
RLS Enabled: β
YES
Policies Found: 2
Status: β
PROPERLY CONFIGURED
Policies:
βββ "Public sees published" (SELECT)
β βββ USING: (published = true)
βββ "Authors manage own" (ALL)
βββ USING: (auth.uid() = author_id)
Test Results:
βββ Anon SELECT: Only published posts (correct)
βββ Anon INSERT: β Blocked (correct)
βββ Cross-user access: β Blocked (correct)
βββ Filter bypass: β Blocked (correct)
3. orders
RLS Enabled: β
YES
Policies Found: 1
Status: π P1 - PARTIAL ISSUE
Policies:
βββ "Users see own orders" (SELECT)
βββ USING: (auth.uid() = user_id)
Issue Found:
βββ No INSERT policy - users can't create orders via API
βββ No UPDATE policy - users can't modify their orders
βββ This may be intentional (orders via Edge Functions)
Recommendation: Document if intentional, or add policies:
```sql
CREATE POLICY "Users insert own orders"
ON orders FOR INSERT
WITH CHECK (auth.uid() = user_id);
```
4. comments
RLS Enabled: β
YES
Policies Found: 2
Status: π P1 - BYPASS POSSIBLE
Policies:
βββ "Anyone can read" (SELECT)
β βββ USING: (true) β Too permissive
βββ "Users comment on posts" (INSERT)
βββ WITH CHECK: (auth.uid() = user_id)
Issue Found:
βββ SELECT policy allows reading all comments
including user_id, enabling user correlation
Recommendation:
```sql
-- Use a view to hide user_id
CREATE VIEW public.comments_public AS
SELECT id, post_id, content, created_at FROM comments;
```
5. settings
RLS Enabled: β NO
Status: π΄ P0 - NO RLS PROTECTION
Contains sensitive configuration!
Immediate action required.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Summary
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
RLS Disabled: 2 tables (users, settings) β CRITICAL
RLS Enabled: 6 tables
βββ Properly Configured: 3
βββ Partial Issues: 2
βββ Major Issues: 1
Bypass Tests:
βββ Unauthenticated access: 2 tables vulnerable
βββ Cross-user access: 0 tables vulnerable
βββ Filter bypass: 0 tables vulnerable
βββ Join exploitation: 1 table allows data leakage
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Context Output
{
"rls_audit": {
"timestamp": "2025-01-31T10:45:00Z",
"tables_audited": 8,
"summary": {
"rls_disabled": 2,
"rls_enabled": 6,
"properly_configured": 3,
"partial_issues": 2,
"major_issues": 1
},
"findings": [
{
"table": "users",
"rls_enabled": false,
"severity": "P0",
"issue": "No RLS protection",
"operations_exposed": ["SELECT", "INSERT", "UPDATE", "DELETE"]
},
{
"table": "comments",
"rls_enabled": true,
"severity": "P1",
"issue": "Overly permissive SELECT policy",
"detail": "user_id exposed enabling correlation"
}
]
}
}
Common RLS Patterns
Good: User owns their data
CREATE POLICY "Users own their data"
ON user_data FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
Good: Public read, authenticated write
CREATE POLICY "Public read" ON posts
FOR SELECT USING (published = true);
CREATE POLICY "Author write" ON posts
FOR INSERT WITH CHECK (auth.uid() = author_id);
CREATE POLICY "Author update" ON posts
FOR UPDATE USING (auth.uid() = author_id);
Bad: Using (true)
CREATE POLICY "Anyone" ON secrets
FOR SELECT USING (true);
Bad: Forgetting WITH CHECK
CREATE POLICY "Insert" ON posts
FOR INSERT WITH CHECK (true);
RLS Bypass Documentation
For each bypass found, the skill provides:
- Description of the vulnerability
- Proof of concept query
- Impact assessment
- Fix with SQL code
- Documentation link
MANDATORY: Progressive Context File Updates
β οΈ This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.
Critical Rule: Write As You Go
DO NOT batch all writes at the end. Instead:
- Before testing each table β Log the action to
.sb-pentest-audit.log
- After each RLS finding β Immediately update
.sb-pentest-context.json
- After each test completes β Log the result to
.sb-pentest-audit.log
This ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
Required Actions (Progressive)
-
Update .sb-pentest-context.json with results:
{
"rls_audit": {
"timestamp": "...",
"tables_audited": 8,
"summary":