关于 supabase-audit-buckets-read
用于 Supabase 安全审计的技能,通过测试存储桶中的文件访问来验证权限。它会检查文件列表、元数据、样本下载和公开 URL,并逐步记录发现与证据。
主要功能
- 01测试文件列表和元数据访问
- 02下载样本并检查内容类型
- 03检查公开 URL 可访问性
- 04识别敏感文件与内容
- 05逐步记录发现和证据
适用场景
- 01验证存储桶的 RLS 权限
- 02查找公开暴露的敏感文件
- 03记录可访问文件及审计证据
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-audit-buckets-read安装后在 Claude Code 中输入/supabase-audit-buckets-read确认已加载。
详细介绍
存储桶文件访问测试
🔴 严重:必须渐进式更新文件
你必须随进度写入上下文文件,而不是只在最后写入。
- 每测试完一个存储桶后,立即写入
.sb-pentest-context.json- 每次文件访问测试之前和之后,都要记录到
.sb-pentest-audit.log- 不要等到技能执行完毕才更新文件
- 如果技能崩溃或中断,之前的所有发现都必须已经保存
此要求不可协商。不渐进式写入属于严重错误。
此技能会测试存储桶中的实际文件访问情况,以验证权限。
何时使用此技能
- 列出存储桶后,用于验证实际访问权限
- 测试存储 RLS 策略的有效性
- 检查是否暴露了敏感文件
- 记录哪些文件可以访问
前提条件
- 已列出存储桶(如有需要会自动调用)
- 有可用的 anon key
工作原理
此技能会尝试:
- 列出文件:列出每个存储桶中的文件
- 读取文件元数据
- 下载示例文件(用于验证内容类型)
- 检查公共 URL 的访问情况
重要: 此操作为只读操作,不会修改或删除任何文件。
测试方法
| 存储桶类型 | 执行的测试 |
|---|---|
| 公共 | 直接 URL 访问、列表、元数据 |
| 私有 | 使用 anon key 通过 API 列表查询、验证已认证访问 |
用法
基本读取测试
Test read access on storage buckets
指定存储桶
Test file access on the documents bucket
仅列出文件(不下载)
List accessible files without downloading content
输出格式
═══════════════════════════════════════════════════════════
BUCKET FILE ACCESS TEST
═══════════════════════════════════════════════════════════
Project: abc123def.supabase.co
Buckets Tested: 5
─────────────────────────────────────────────────────────
avatars (Public Bucket)
─────────────────────────────────────────────────────────
Status: ✅ Expected Access
Files Found: 1,247
Sample Files:
├── user-550e8400.jpg (45KB) - Public URL works
├── user-6ba7b810.png (32KB) - Public URL works
└── default.png (12KB) - Public URL works
Access Methods:
├── Public URL: ✅ Accessible
├── API Listing: ✅ Works
└── Metadata: ✅ Visible
Assessment: Expected behavior for avatar storage.
─────────────────────────────────────────────────────────
documents (Private Bucket)
─────────────────────────────────────────────────────────
Status: ✅ PROPERLY PROTECTED
Files Found: 0 (via anon key)
Access Methods:
├── Public URL: ❌ 403 Forbidden (correct)
├── API Listing: ❌ Empty result (RLS working)
└── Metadata: ❌ Not accessible (correct)
Assessment: RLS policies working correctly.
─────────────────────────────────────────────────────────
uploads (Public Bucket)
─────────────────────────────────────────────────────────
Status: 🟠 P1 - SENSITIVE FILES EXPOSED
Files Found: 3,891
Sensitive Files Detected:
├── 🔴 invoice-2025-001.pdf - Contains financial data
├── 🔴 contract-signed.pdf - Legal document
├── 🔴 id-verification.jpg - Personal ID photo!
├── ⚠️ database-export.csv - Possible data export
└── ⚠️ config.json - Configuration file
File Types Distribution:
├── PDF: 1,234 (31%)
├── Images: 2,100 (54%)
├── Documents: 450 (12%)
└── Other: 107 (3%)
Assessment: Bucket contains sensitive files that should not be public!
─────────────────────────────────────────────────────────
backups (Public - CRITICAL)
─────────────────────────────────────────────────────────
Status: 🔴 P0 - CRITICAL DATA EXPOSURE
Files Found: 45
Exposed Files:
├── 🔴 db-backup-2025-01-30.sql (125MB) - DATABASE BACKUP!
├── 🔴 db-backup-2025-01-29.sql (124MB) - DATABASE BACKUP!
├── 🔴 users-export.csv (2.3MB) - USER DATA EXPORT!
├── 🔴 secrets.env (1KB) - ENVIRONMENT SECRETS!
└── 🔴 .env.production (1KB) - PRODUCTION SECRETS!
Sample Content (secrets.env):
┌─────────────────────────────────────────────────────────┐
│ STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxx │
│ DATABASE_URL=postgresql://postgres:xxx@... │
│ JWT_SECRET=super-secret-jwt-key │
└─────────────────────────────────────────────────────────┘
⚠️ IMMEDIATE ACTION REQUIRED:
1. Make bucket private NOW
2. Rotate ALL exposed secrets
3. Delete backup files from public access
4. Audit for unauthorized access in logs
─────────────────────────────────────────────────────────
temp (Private Bucket)
─────────────────────────────────────────────────────────
Status: ✅ PROPERLY PROTECTED
Files Found: 0 (via anon key)
Assessment: Access correctly restricted.
─────────────────────────────────────────────────────────
Summary
─────────────────────────────────────────────────────────
P0 Critical: 1 bucket (backups - DB dumps & secrets exposed)
P1 High: 1 bucket (uploads - sensitive documents in public bucket)
Protected: 2 buckets (documents, temp)
Expected: 1 bucket (avatars)
Total Files Accessible: 5,183
Sensitive Files Exposed: 52
Secret Files Exposed: 3
Immediate Actions:
1. 🔴 DELETE or make private 'backups' bucket
2. 🔴 Rotate Stripe key, DB password, JWT secret
3. 🟠 Move sensitive files from 'uploads' to private bucket
4. Review all 52 sensitive files for exposure impact
═══════════════════════════════════════════════════════════
敏感文件检测
此技能通过以下方式识别敏感文件:
文件名模式
| 模式 | 风险 | 类型 |
|---|---|---|
*.sql, backup* | P0 | 数据库转储 |
.env*, *secrets* | P0 | 密钥文件 |
*password*, *credential* | P0 | 凭据 |
*invoice*, *payment* | P1 | 财务 |
*contract*, *agreement* | P1 | 法律 |
*id*, *passport*, *license* | P1 | 身份信息 |
*export*, *dump* | P1 | 数据导出 |
内容检测
对于可访问的文件,此技能会抽样检查内容中的:
- API 密钥(例如
sk_live_、pk_test_等模式) - 数据库凭据
- JWT 密钥
- 个人信息模式
上下文输出
{
"storage_access": {
"timestamp": "2025-01-31T11:30:00Z",
"buckets_tested": 5,
"findings": [
{
"bucket": "backups",
"severity": "P0",
"public": true,
"files_exposed": 45,
"sensitive_files": [
{
"path": "db-backup-2025-01-30.sql",
"size": 131072000,
"type": "database_backup",
"risk": "Full database accessible"
},
{
"path": "secrets.env",
"size": 1024,
"type": "secrets",
"exposed_secrets": ["STRIPE_SECRET_KEY", "DATABASE_URL", "JWT_SECRET"]
}
]
}
],
"summary": {
"total_files_accessible": 5183,
"sensitive_files": 52,
"secret_files": 3
}
}
}
修复步骤
针对暴露的密钥
# 1. Rotate Stripe keys
# Stripe Dashboard → Developers → API Keys → Roll Keys
# 2. Change database password
# Supabase Dashboard → Settings → Database → Reset Password
# 3. Regenerate JWT secret
# Supabase Dashboard → Settings → API → Regenerate JWT Secret
# 4. Update application environment variables
# Redeploy with new secrets
修复公共存储桶
-- Make bucket private
UPDATE storage.buckets
SET public = false
WHERE name = 'backups';
-- Delete sensitive files or move to secure location
DELETE FROM storage.objects
WHERE bucket_id = 'backups';
针对上传存储桶
-- Add RLS to restrict access
CREATE POLICY "Users access own uploads"
ON storage.objects FOR ALL
USING (
bucket_id = 'uploads'
AND auth.uid()::text = (storage.foldername(name))[1]
);
常见问题
❌ 问题: 无法列出私有存储桶中的文件 ✅ 解决方案: 这是正确的行为,说明 RLS 正在生效。
❌ 问题: 要扫描的文件数量过多 ✅ 解决方案: 对大型存储桶使用抽样模式。
❌ 问题: 文件下载失败 ✅ 解决方案: 可能是 RLS 限制或网络问题。
强制要求:渐进式更新上下文文件
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,不能只在最后更新。
关键规则:随进度写入
不要把所有写入操作都留到最后。请按以下步骤操作:
- 测试每个存储桶之前 → 将操作记录到
.sb-pentest-audit.log - 发现每个敏感文件之后 → 立即更新
.sb-pentest-context.json - 完成每个存储桶之后 → 记录摘要
这样可以确保即使技能被中断、崩溃或超时,到那时为止的所有发现都能得到保留。
必须执行的操作(渐进式)
-
更新
.sb-pentest-context.json,写入测试结果:{ "storage_access": { "timestamp": "...", "buckets_tested": 5, "findings": [ ... ], "summary": { "total_files_accessible": 5183, ... } } } -
记录到
.sb-pentest-audit.log:[TIMESTAMP] [supabase-audit-buckets-read] [START] Testing bucket file access [TIMESTAMP] [supabase-audit-buckets-read] [FINDING] P0: backups bucket has exposed secrets [TIMESTAMP] [supabase-audit-buckets-read] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,请先创建文件再写入。
不更新上下文文件是不可接受的。
强制要求:收集证据
📁 证据目录: .sb-pentest-evidence/04-storage-audit/buckets/
需要创建的证据文件
| 文件 | 内容 |
|---|---|
buckets/[name]/file-list.json | 在存储桶中找到的文件 |
buckets/[name]/sensitive-files.json | 检测到的敏感文件 |
buckets/[name]/sample-contents/ | 已编辑的内容样本 |
暴露敏感文件时的证据格式
{
"evidence_id": "STG-READ-001",
"timestamp": "2025-01-31T10:40:00Z",
"category": "storage-audit",
"type": "file_access",
"severity": "P0",
"bucket": "backups",
"public": true,
"files_found": 45,
"sensitive_files": [
{
"path": "db-backup-2025-01-30.sql",
"size": 131072000,
"type": "database_backup",
"public_url": "https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql",
"curl_command": "curl -o backup.sql 'https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql'"
},
{
"path": "secrets.env",
"size": 1024,
"type": "secrets_file",
"content_sample": "STRIPE_SECRET_KEY=sk_live_[REDACTED]\nDATABASE_URL=postgresql://[REDACTED]",
"exposed_secrets": ["STRIPE_SECRET_KEY", "DATABASE_URL", "JWT_SECRET"]
}
],
"impact": {
"data_breach": true,
"secrets_exposed": true,
"affected_records": "All database records",
"credentials_to_rotate": ["Stripe API key", "Database password", "JWT secret"]
}
}
添加到 curl-commands.sh
# === STORAGE FILE ACCESS TESTS ===
# List files in backups bucket
curl -s "$SUPABASE_URL/storage/v1/object/list/backups" \
-H "apikey: $ANON_KEY"
# Direct access to public file (P0 if accessible)
curl -I "https://abc123def.supabase.co/storage/v1/object/public/backups/secrets.env"
# Download exposed backup (for evidence - be careful with size)
# curl -o evidence-backup-sample.sql "https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql" | head -1000
相关技能
supabase-audit-buckets-list— 先列出存储桶supabase-audit-buckets-public— 聚焦公开访问问题supabase-report— 生成完整报告
评论
支持 Markdown