supabase-audit-rls

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

RLS Policy Audit

RLS 策略审计

🔴 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.
🔴 严重警告:需逐步更新文件
你必须逐步写入上下文文件,不能只在最后统一写入。
  • 每次发现问题后立即写入
    .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问题

IssueDescriptionSeverity
RLS DisabledTable has no RLS protectionP0
Missing PolicyRLS enabled but no SELECT policyVariable
Overly PermissivePolicy allows too much accessP0-P1
Missing OperationSELECT policy but no INSERT/UPDATE/DELETEP1
USING vs WITH CHECKRead allowed but write inconsistentP1
问题描述严重程度
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头或仅使用匿名密钥

undefined
undefined

2. Cross-User Access

2. 跨用户访问

undefined
undefined

As 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]
undefined
GET /rest/v1/orders?user_id=eq.[user-b-id] Authorization: Bearer [user-a-token]
undefined

3. Filter Bypass

3. 过滤条件绕过

undefined
undefined

Try to bypass filters with OR conditions

尝试用OR条件绕过过滤

GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
undefined
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
undefined

4. Join Exploitation

4. 关联表利用

undefined
undefined

Try to access data through related tables

尝试通过关联表访问数据

GET /rest/v1/comments?select=,posts()
undefined
GET /rest/v1/comments?select=,posts()
undefined

5. RPC Bypass

5. RPC绕过

undefined
undefined

Check if RPC functions bypass RLS

检查RPC函数是否绕过RLS

POST /rest/v1/rpc/get_all_users
undefined
POST /rest/v1/rpc/get_all_users
undefined

Usage

使用方法

Basic RLS Audit

基础RLS审计

Audit RLS policies on my Supabase project
Audit RLS policies on my Supabase project

Specific Table

指定数据表

Test RLS on the users table
Test RLS on the users table

With 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);
  1. posts RLS已启用: ✅ 是 已发现策略: 2 状态: ✅ 配置正确
    策略: ├── "Public sees published" (SELECT) │ └── USING: (published = true) └── "Authors manage own" (ALL) └── USING: (auth.uid() = author_id)
    测试结果: ├── 匿名用户SELECT: 仅返回已发布内容(正确) ├── 匿名用户INSERT: ❌ 被阻止(正确) ├── 跨用户访问: ❌ 被阻止(正确) └── 过滤条件绕过: ❌ 被阻止(正确)
  2. 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);
  3. 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;
  4. settings RLS已启用: ❌ 否 状态: 🔴 P0 - 无RLS保护
    包含敏感配置信息! 需立即处理。
───────────────────────────────────────────────────────── 总结 ─────────────────────────────────────────────────────────
RLS未启用: 2个数据表(users、settings)← 严重问题 RLS已启用: 6个数据表 ├── 配置正确: 3个 ├── 部分问题: 2个 └── 重大问题: 1个
绕过测试结果: ├── 未认证访问: 2个数据表存在漏洞 ├── 跨用户访问: 0个数据表存在漏洞 ├── 过滤条件绕过: 0个数据表存在漏洞 └── 关联表利用: 1个数据表存在数据泄露
═══════════════════════════════════════════════════════════
undefined

Context 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:
  1. Description of the vulnerability
  2. Proof of concept query
  3. Impact assessment
  4. Fix with SQL code
  5. Documentation link
对于每个发现的绕过漏洞,本技能会提供:
  1. 漏洞描述
  2. 概念验证(PoC)查询语句
  3. 影响评估
  4. 包含SQL代码的修复方案
  5. 文档链接

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:
  1. Before testing each table → Log the action to
    .sb-pentest-audit.log
  2. After each RLS finding → Immediately update
    .sb-pentest-context.json
  3. 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.
禁止批量写入所有内容。正确流程:
  1. 测试每个数据表前 → 将操作记录到
    .sb-pentest-audit.log
  2. 每次发现RLS问题后 → 立即更新
    .sb-pentest-context.json
  3. 每次测试完成后 → 将结果记录到
    .sb-pentest-audit.log
此规则确保如果技能被中断、崩溃或超时,所有已完成的测试结果都能被保留。

Required Actions (Progressive)

强制逐步操作

  1. Update
    .sb-pentest-context.json
    with results:
    json
    {
      "rls_audit": {
        "timestamp": "...",
        "tables_audited": 8,
        "summary": { "rls_disabled": 2, ... },
        "findings": [ ... ]
      }
    }
  2. 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
  3. If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
  1. 更新
    .sb-pentest-context.json
    记录结果:
    json
    {
      "rls_audit": {
        "timestamp": "...",
        "tables_audited": 8,
        "summary": { "rls_disabled": 2, ... },
        "findings": [ ... ]
      }
    }
  2. 记录到
    .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已更新
  3. 如果文件不存在,先创建再写入。
未更新上下文文件的行为是不被接受的。

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

需创建的证据文件

FileContent
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
文件内容
rls-tests/[table]-anon.json
匿名访问测试结果
rls-tests/[table]-auth.json
已认证用户访问测试结果
rls-tests/cross-user-test.json
跨用户访问尝试记录

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
undefined
bash
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"
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"
undefined
curl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)"
-H "apikey: $ANON_KEY"
undefined

Related Skills

相关技能

  • supabase-audit-tables-list
    — List tables first
  • supabase-audit-tables-read
    — See actual data exposure
  • supabase-audit-rpc
    — RPC functions can bypass RLS
  • supabase-report
    — Full security report
  • supabase-audit-tables-list
    — 先列出所有数据表
  • supabase-audit-tables-read
    — 查看实际数据泄露情况
  • supabase-audit-rpc
    — RPC函数可能绕过RLS
  • supabase-report
    — 生成完整安全报告