supabase-audit-rls
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRLS Policy Audit
RLS 策略审计
🔴 CRITICAL: PROGRESSIVE FILE UPDATES REQUIREDYou MUST write to context files AS YOU GO, not just at the end.
- Write to
IMMEDIATELY after each finding.sb-pentest-context.json- Log to
BEFORE and AFTER each test.sb-pentest-audit.log- 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.
🔴 严重警告:需逐步更新文件你必须逐步写入上下文文件,不能只在最后统一写入。
- 每次发现问题后立即写入
.sb-pentest-context.json- 每次测试前后都要记录到
.sb-pentest-audit.log- 禁止等到技能执行完毕再更新文件
- 如果技能崩溃或被中断,所有已发现的问题必须已保存
此要求为强制项,未逐步更新属于严重错误。
本技能用于测试行级安全(RLS)策略的常见漏洞与配置错误。
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
- 发现数据表存在数据泄露后
- 验证RLS策略是否正确实现
- 测试常见的RLS绕过技术
- 作为全面安全审计的一部分
Prerequisites
前置条件
- Tables listed
- Anon key available
- Preferably also test with an authenticated user token
- 已列出目标数据表
- 拥有匿名访问密钥(Anon key)
- 最好同时使用已认证用户的令牌进行测试
Understanding RLS
理解RLS
Row Level Security in Supabase/PostgreSQL:
sql
-- Enable RLS on a table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Create a policy
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.
Supabase/PostgreSQL中的行级安全:
sql
-- 为数据表启用RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- 创建策略
CREATE POLICY "Users see own posts"
ON posts FOR SELECT
USING (auth.uid() = author_id);如果启用了RLS但未创建任何策略,所有访问都会被阻止。
Common RLS Issues
常见RLS问题
| 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 |
| 问题 | 描述 | 严重程度 |
|---|---|---|
| RLS未启用 | 数据表无RLS保护 | P0 |
| 缺少策略 | 启用RLS但无SELECT策略 | 可变 |
| 权限过度宽松 | 策略允许的访问范围过大 | P0-P1 |
| 缺少操作权限 | 有SELECT策略但无INSERT/UPDATE/DELETE策略 | P1 |
| USING与WITH CHECK不一致 | 读取权限允许但写入权限不匹配 | P1 |
Test Vectors
测试向量
The skill tests these common bypass scenarios:
本技能测试以下常见绕过场景:
1. Unauthenticated Access
1. 未认证访问
GET /rest/v1/users?select=*GET /rest/v1/users?select=*No Authorization header or with anon key only
不携带Authorization头或仅使用匿名密钥
undefinedundefined2. Cross-User Access
2. 跨用户访问
undefinedundefinedAs user A, try to access user B's data
以用户A的身份,尝试访问用户B的数据
GET /rest/v1/orders?user_id=eq.[user-b-id]
Authorization: Bearer [user-a-token]
undefinedGET /rest/v1/orders?user_id=eq.[user-b-id]
Authorization: Bearer [user-a-token]
undefined3. Filter Bypass
3. 过滤条件绕过
undefinedundefinedTry to bypass filters with OR conditions
尝试用OR条件绕过过滤
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
undefinedGET /rest/v1/posts?or=(published.eq.true,published.eq.false)
undefined4. Join Exploitation
4. 关联表利用
undefinedundefinedTry to access data through related tables
尝试通过关联表访问数据
GET /rest/v1/comments?select=,posts()
undefinedGET /rest/v1/comments?select=,posts()
undefined5. RPC Bypass
5. RPC绕过
undefinedundefinedCheck if RPC functions bypass RLS
检查RPC函数是否绕过RLS
POST /rest/v1/rpc/get_all_users
undefinedPOST /rest/v1/rpc/get_all_users
undefinedUsage
使用方法
Basic RLS Audit
基础RLS审计
Audit RLS policies on my Supabase projectAudit RLS policies on my Supabase projectSpecific Table
指定数据表
Test RLS on the users tableTest RLS on the users tableWith Authenticated User
使用已认证用户
Test RLS policies using this user token: eyJ...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
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
RLS 策略审计
═══════════════════════════════════════════════════════════
项目: abc123def.supabase.co
已审计数据表: 8
─────────────────────────────────────────────────────────
各数据表RLS状态
─────────────────────────────────────────────────────────
1. users
RLS已启用: ❌ 否
状态: 🔴 P0 - 无RLS保护
所有操作均不受限制!
测试结果:
├── 匿名用户SELECT: ✓ 返回全部1247行数据
├── 匿名用户INSERT: ✓ 执行成功(已回滚测试)
├── 匿名用户UPDATE: ✓ 可执行成功
└── 匿名用户DELETE: ✓ 可执行成功
立即修复方案:
```sql
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users see own data"
ON users FOR ALL
USING (auth.uid() = id);-
posts RLS已启用: ✅ 是 已发现策略: 2 状态: ✅ 配置正确策略: ├── "Public sees published" (SELECT) │ └── USING: (published = true) └── "Authors manage own" (ALL) └── USING: (auth.uid() = author_id)测试结果: ├── 匿名用户SELECT: 仅返回已发布内容(正确) ├── 匿名用户INSERT: ❌ 被阻止(正确) ├── 跨用户访问: ❌ 被阻止(正确) └── 过滤条件绕过: ❌ 被阻止(正确)
-
orders RLS已启用: ✅ 是 已发现策略: 1 状态: 🟠 P1 - 部分问题策略: └── "Users see own orders" (SELECT) └── USING: (auth.uid() = user_id)发现问题: ├── 无INSERT策略 - 用户无法通过API创建订单 ├── 无UPDATE策略 - 用户无法修改自己的订单 └── 此情况可能为有意设计(通过Edge Functions处理订单)建议: 若为有意设计则需文档说明,否则添加策略:sql
CREATE POLICY "Users insert own orders" ON orders FOR INSERT WITH CHECK (auth.uid() = user_id); -
comments RLS已启用: ✅ 是 已发现策略: 2 状态: 🟠 P1 - 存在绕过可能策略: ├── "Anyone can read" (SELECT) │ └── USING: (true) ← 权限过于宽松 └── "Users comment on posts" (INSERT) └── WITH CHECK: (auth.uid() = user_id)发现问题: └── SELECT策略允许读取所有评论 包括user_id字段,可能导致用户关联泄露建议:sql
-- 使用视图隐藏user_id CREATE VIEW public.comments_public AS SELECT id, post_id, content, created_at FROM comments; -
settings RLS已启用: ❌ 否 状态: 🔴 P0 - 无RLS保护包含敏感配置信息! 需立即处理。
─────────────────────────────────────────────────────────
总结
─────────────────────────────────────────────────────────
RLS未启用: 2个数据表(users、settings)← 严重问题
RLS已启用: 6个数据表
├── 配置正确: 3个
├── 部分问题: 2个
└── 重大问题: 1个
绕过测试结果:
├── 未认证访问: 2个数据表存在漏洞
├── 跨用户访问: 0个数据表存在漏洞
├── 过滤条件绕过: 0个数据表存在漏洞
└── 关联表利用: 1个数据表存在数据泄露
═══════════════════════════════════════════════════════════
undefinedContext Output
上下文输出
json
{
"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"
}
]
}
}json
{
"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
常见RLS模式
Good: User owns their data
良好实践:用户拥有自身数据
sql
CREATE POLICY "Users own their data"
ON user_data FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);sql
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
良好实践:公开可读,认证可写
sql
-- Anyone can read
CREATE POLICY "Public read" ON posts
FOR SELECT USING (published = true);
-- Only authors can write
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);sql
-- 任何人可读取
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)
不良实践:使用(true)
sql
-- ❌ Too permissive
CREATE POLICY "Anyone" ON secrets
FOR SELECT USING (true);sql
-- ❌ 权限过于宽松
CREATE POLICY "Anyone" ON secrets
FOR SELECT USING (true);Bad: Forgetting WITH CHECK
不良实践:遗漏WITH CHECK
sql
-- ❌ Users can INSERT any user_id
CREATE POLICY "Insert" ON posts
FOR INSERT WITH CHECK (true); -- Should check user_id!sql
-- ❌ 用户可插入任意user_id
CREATE POLICY "Insert" ON posts
FOR INSERT WITH CHECK (true); -- 应检查user_id!RLS Bypass Documentation
RLS绕过文档
For each bypass found, the skill provides:
- Description of the vulnerability
- Proof of concept query
- Impact assessment
- Fix with SQL code
- Documentation link
对于每个发现的绕过漏洞,本技能会提供:
- 漏洞描述
- 概念验证(PoC)查询语句
- 影响评估
- 包含SQL代码的修复方案
- 文档链接
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.
禁止批量写入所有内容。正确流程:
- 测试每个数据表前 → 将操作记录到
.sb-pentest-audit.log - 每次发现RLS问题后 → 立即更新
.sb-pentest-context.json - 每次测试完成后 → 将结果记录到
.sb-pentest-audit.log
此规则确保如果技能被中断、崩溃或超时,所有已完成的测试结果都能被保留。
Required Actions (Progressive)
强制逐步操作
-
Updatewith results:
.sb-pentest-context.jsonjson{ "rls_audit": { "timestamp": "...", "tables_audited": 8, "summary": { "rls_disabled": 2, ... }, "findings": [ ... ] } } -
Log to:
.sb-pentest-audit.log[TIMESTAMP] [supabase-audit-rls] [START] Auditing RLS policies [TIMESTAMP] [supabase-audit-rls] [FINDING] P0: users table has no RLS [TIMESTAMP] [supabase-audit-rls] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
-
更新记录结果:
.sb-pentest-context.jsonjson{ "rls_audit": { "timestamp": "...", "tables_audited": 8, "summary": { "rls_disabled": 2, ... }, "findings": [ ... ] } } -
记录到:
.sb-pentest-audit.log[TIMESTAMP] [supabase-audit-rls] [START] 开始审计RLS策略 [TIMESTAMP] [supabase-audit-rls] [FINDING] P0: users表未启用RLS [TIMESTAMP] [supabase-audit-rls] [CONTEXT_UPDATED] .sb-pentest-context.json已更新 -
如果文件不存在,先创建再写入。
未更新上下文文件的行为是不被接受的。
MANDATORY: Evidence Collection
强制要求:收集证据
📁 Evidence Directory:
.sb-pentest-evidence/03-api-audit/rls-tests/📁 证据目录:
.sb-pentest-evidence/03-api-audit/rls-tests/Evidence Files to Create
需创建的证据文件
| File | Content |
|---|---|
| Anonymous access test results |
| Authenticated access test results |
| Cross-user access attempts |
| 文件 | 内容 |
|---|---|
| 匿名访问测试结果 |
| 已认证用户访问测试结果 |
| 跨用户访问尝试记录 |
Evidence Format (RLS Bypass)
RLS绕过证据格式
json
{
"evidence_id": "RLS-001",
"timestamp": "2025-01-31T10:25:00Z",
"category": "api-audit",
"type": "rls_test",
"severity": "P0",
"table": "users",
"rls_enabled": false,
"tests": [
{
"test_name": "anon_select",
"description": "Anonymous user SELECT access",
"request": {
"curl_command": "curl -s '$URL/rest/v1/users?select=*&limit=5' -H 'apikey: $ANON_KEY'"
},
"response": {
"status": 200,
"rows_returned": 5,
"total_accessible": 1247
},
"result": "VULNERABLE",
"impact": "All user data accessible without authentication"
},
{
"test_name": "anon_insert",
"description": "Anonymous user INSERT access",
"request": {
"curl_command": "curl -X POST '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -d '{...}'"
},
"response": {
"status": 201
},
"result": "VULNERABLE",
"impact": "Can create arbitrary user records"
}
],
"remediation_sql": "ALTER TABLE users ENABLE ROW LEVEL SECURITY;\nCREATE POLICY \"Users see own data\" ON users FOR SELECT USING (auth.uid() = id);"
}json
{
"evidence_id": "RLS-001",
"timestamp": "2025-01-31T10:25:00Z",
"category": "api-audit",
"type": "rls_test",
"severity": "P0",
"table": "users",
"rls_enabled": false,
"tests": [
{
"test_name": "anon_select",
"description": "匿名用户SELECT访问测试",
"request": {
"curl_command": "curl -s '$URL/rest/v1/users?select=*&limit=5' -H 'apikey: $ANON_KEY'"
},
"response": {
"status": 200,
"rows_returned": 5,
"total_accessible": 1247
},
"result": "存在漏洞",
"impact": "所有用户数据可被未认证用户访问"
},
{
"test_name": "anon_insert",
"description": "匿名用户INSERT访问测试",
"request": {
"curl_command": "curl -X POST '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -d '{...}'"
},
"response": {
"status": 201
},
"result": "存在漏洞",
"impact": "可创建任意用户记录"
}
],
"remediation_sql": "ALTER TABLE users ENABLE ROW LEVEL SECURITY;\nCREATE POLICY \"Users see own data\" ON users FOR SELECT USING (auth.uid() = id);"
}Add to curl-commands.sh
添加到curl-commands.sh
bash
undefinedbash
undefined=== RLS BYPASS TESTS ===
=== RLS 绕过测试 ===
Test anon access to users table
测试匿名用户访问users表
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5"
-H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"
-H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5"
-H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"
-H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"
Test filter bypass
测试过滤条件绕过
curl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)"
-H "apikey: $ANON_KEY"
-H "apikey: $ANON_KEY"
undefinedcurl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)"
-H "apikey: $ANON_KEY"
-H "apikey: $ANON_KEY"
undefinedRelated Skills
相关技能
- — List tables first
supabase-audit-tables-list - — See actual data exposure
supabase-audit-tables-read - — RPC functions can bypass RLS
supabase-audit-rpc - — Full security report
supabase-report
- — 先列出所有数据表
supabase-audit-tables-list - — 查看实际数据泄露情况
supabase-audit-tables-read - — RPC函数可能绕过RLS
supabase-audit-rpc - — 生成完整安全报告
supabase-report