supabase-audit-rls by yoanbernabeu/supabase-pentest-skills
npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-audit-rls🔴 关键:需要渐进式文件更新
你必须在审计过程中就写入上下文文件,而不是等到最后。
- 每次发现后立即写入
.sb-pentest-context.json- 每次测试前后记录到
.sb-pentest-audit.log- 不要等到技能执行完毕才更新文件
- 如果技能崩溃或被中断,所有之前的发现必须已经保存
这不是可选的。不进行渐进式写入是严重错误。
此技能用于测试行级安全策略是否存在常见漏洞和错误配置。
Supabase/PostgreSQL 中的行级安全:
-- 在表上启用 RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- 创建策略
CREATE POLICY "Users see own posts"
ON posts FOR SELECT
USING (auth.uid() = author_id);
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
如果启用了 RLS 但不存在任何策略,则所有访问都会被阻止。
| 问题 | 描述 | 严重性 |
|---|---|---|
| RLS 禁用 | 表没有 RLS 保护 | P0 |
| 缺少策略 | RLS 已启用但缺少 SELECT 策略 | 可变 |
| 过于宽松 | 策略允许过多访问 | P0-P1 |
| 缺少操作 | 有 SELECT 策略但无 INSERT/UPDATE/DELETE | P1 |
| USING 与 WITH CHECK | 允许读取但写入不一致 | P1 |
此技能测试以下常见绕过场景:
GET /rest/v1/users?select=*
# 无 Authorization 头或仅使用匿名密钥
# 以用户 A 身份,尝试访问用户 B 的数据
GET /rest/v1/orders?user_id=eq.[user-b-id]
Authorization: Bearer [user-a-token]
# 尝试使用 OR 条件绕过过滤器
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
# 尝试通过相关表访问数据
GET /rest/v1/comments?select=*,posts(*)
# 检查 RPC 函数是否绕过 RLS
POST /rest/v1/rpc/get_all_users
审计我的 Supabase 项目上的 RLS 策略
测试 users 表上的 RLS
使用此用户令牌测试 RLS 策略:eyJ...
═══════════════════════════════════════════════════════════
RLS 策略审计
═══════════════════════════════════════════════════════════
项目:abc123def.supabase.co
已审计表:8
─────────────────────────────────────────────────────────
各表 RLS 状态
─────────────────────────────────────────────────────────
1. users
RLS 已启用:❌ 否
状态:🔴 P0 - 无 RLS 保护
所有操作不受限制地允许!
测试结果:
├── 匿名 SELECT:✓ 返回所有 1,247 行
├── 匿名 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);
```
2. posts
RLS 已启用:✅ 是
找到策略:2
状态:✅ 正确配置
策略:
├── "Public sees published" (SELECT)
│ └── USING: (published = true)
└── "Authors manage own" (ALL)
└── USING: (auth.uid() = author_id)
测试结果:
├── 匿名 SELECT:仅已发布的帖子(正确)
├── 匿名 INSERT:❌ 被阻止(正确)
├── 跨用户访问:❌ 被阻止(正确)
└── 过滤器绕过:❌ 被阻止(正确)
3. 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);
```
4. 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;
```
5. settings
RLS 已启用:❌ 否
状态:🔴 P0 - 无 RLS 保护
包含敏感配置!
需要立即采取行动。
─────────────────────────────────────────────────────────
摘要
─────────────────────────────────────────────────────────
RLS 禁用:2 个表 (users, settings) ← 关键
RLS 启用:6 个表
├── 正确配置:3
├── 部分问题:2
└── 主要问题:1
绕过测试:
├── 未认证访问:2 个表存在漏洞
├── 跨用户访问:0 个表存在漏洞
├── 过滤器绕过:0 个表存在漏洞
└── 连接利用:1 个表允许数据泄露
═══════════════════════════════════════════════════════════
{
"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"
}
]
}
}
CREATE POLICY "Users own their data"
ON user_data FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- 任何人都可以读取
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);
-- ❌ 过于宽松
CREATE POLICY "Anyone" ON secrets
FOR SELECT USING (true);
-- ❌ 用户可以 INSERT 任何 user_id
CREATE POLICY "Insert" ON posts
FOR INSERT WITH CHECK (true); -- 应该检查 user_id!
对于发现的每个绕过,技能提供:
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是仅在最后更新。
不要在最后批量写入所有内容。而是:
.sb-pentest-audit.log.sb-pentest-context.json.sb-pentest-audit.log这确保了如果技能被中断、崩溃或超时,所有到该点为止的发现都会被保留。
更新 .sb-pentest-context.json 并包含结果:
{
"rls_audit": {
"timestamp": "...",
"tables_audited": 8,
"summary": { "rls_disabled": 2, ... },
"findings": [ ... ]
}
}
记录到 .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
如果文件不存在,在写入前创建它们。
未能更新上下文文件是不可接受的。
📁 证据目录: .sb-pentest-evidence/03-api-audit/rls-tests/
| 文件 | 内容 |
|---|---|
rls-tests/[table]-anon.json | 匿名访问测试结果 |
rls-tests/[table]-auth.json | 认证访问测试结果 |
rls-tests/cross-user-test.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);"
}
# === RLS 绕过测试 ===
# 测试对 users 表的匿名访问
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" \
-H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"
# 测试过滤器绕过
curl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)" \
-H "apikey: $ANON_KEY"
supabase-audit-tables-list — 首先列出表supabase-audit-tables-read — 查看实际数据暴露情况supabase-audit-rpc — RPC 函数可能绕过 RLSsupabase-report — 完整安全报告每周安装数
172
仓库
GitHub 星标数
32
首次出现
2026年1月31日
安全审计
安装于
opencode142
claude-code136
codex135
gemini-cli130
github-copilot126
cursor119
🔴 CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED
You MUST write to context files AS YOU GO , not just at the end.
- Write to
.sb-pentest-context.jsonIMMEDIATELY after each finding- Log to
.sb-pentest-audit.logBEFORE 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.
Row Level Security in Supabase/PostgreSQL:
-- 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.
| 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 |
The skill tests these common bypass scenarios:
GET /rest/v1/users?select=*
# No Authorization header or with anon key only
# 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]
# Try to bypass filters with OR conditions
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
# Try to access data through related tables
GET /rest/v1/comments?select=*,posts(*)
# Check if RPC functions bypass RLS
POST /rest/v1/rpc/get_all_users
Audit RLS policies on my Supabase project
Test RLS on the users table
Test RLS policies using this user token: eyJ...
═══════════════════════════════════════════════════════════
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_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"
}
]
}
}
CREATE POLICY "Users own their data"
ON user_data FOR ALL
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- 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);
-- ❌ Too permissive
CREATE POLICY "Anyone" ON secrets
FOR SELECT USING (true);
-- ❌ Users can INSERT any user_id
CREATE POLICY "Insert" ON posts
FOR INSERT WITH CHECK (true); -- Should check user_id!
For each bypass found, the skill provides:
⚠️ This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.
DO NOT batch all writes at the end. Instead:
.sb-pentest-audit.log.sb-pentest-context.json.sb-pentest-audit.logThis ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
Update.sb-pentest-context.json with results:
{
"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.
📁 Evidence Directory: .sb-pentest-evidence/03-api-audit/rls-tests/
| File | Content |
|---|---|
rls-tests/[table]-anon.json | Anonymous access test results |
rls-tests/[table]-auth.json | Authenticated access test results |
rls-tests/cross-user-test.json | Cross-user access attempts |
{
"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);"
}
# === RLS BYPASS TESTS ===
# Test anon access to users table
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" \
-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"
supabase-audit-tables-list — List tables firstsupabase-audit-tables-read — See actual data exposuresupabase-audit-rpc — RPC functions can bypass RLSsupabase-report — Full security reportWeekly Installs
172
Repository
GitHub Stars
32
First Seen
Jan 31, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode142
claude-code136
codex135
gemini-cli130
github-copilot126
cursor119
Azure PostgreSQL 无密码身份验证配置指南:Entra ID 迁移与访问管理
34,800 周安装