supabase-audit-buckets-read by yoanbernabeu/supabase-pentest-skills
npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-audit-buckets-read🔴 关键要求:必须进行渐进式文件更新
你必须在执行过程中就写入上下文文件,而不仅仅是最后才写。
- 测试完每个存储桶后立即写入
.sb-pentest-context.json- 每次文件访问测试前后都要记录到
.sb-pentest-audit.log- 切勿等到技能执行完毕才更新文件
- 如果技能崩溃或被中断,所有之前的发现必须已经保存
这是强制要求。未能进行渐进式写入是严重错误。
此技能测试存储桶中的实际文件访问以验证权限。
此技能尝试:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
重要提示: 这是只读操作。不会修改或删除任何文件。
| 存储桶类型 | 执行的测试 |
|---|---|
| 公开 | 直接 URL 访问、列出、元数据 |
| 私有 | 使用匿名密钥进行 API 列出、认证访问 |
测试存储桶的读取访问权限
测试 documents 存储桶的文件访问
列出可访问的文件,不下载内容
═══════════════════════════════════════════════════════════
存储桶文件访问测试
═══════════════════════════════════════════════════════════
项目:abc123def.supabase.co
已测试存储桶:5
─────────────────────────────────────────────────────────
avatars(公开存储桶)
─────────────────────────────────────────────────────────
状态:✅ 预期访问
找到文件:1,247
示例文件:
├── user-550e8400.jpg (45KB) - 公共 URL 有效
├── user-6ba7b810.png (32KB) - 公共 URL 有效
└── default.png (12KB) - 公共 URL 有效
访问方法:
├── 公共 URL:✅ 可访问
├── API 列出:✅ 有效
└── 元数据:✅ 可见
评估:头像存储的预期行为。
─────────────────────────────────────────────────────────
documents(私有存储桶)
─────────────────────────────────────────────────────────
状态:✅ 受到适当保护
找到文件:0(通过匿名密钥)
访问方法:
├── 公共 URL:❌ 403 禁止访问(正确)
├── API 列出:❌ 空结果(RLS 正常工作)
└── 元数据:❌ 不可访问(正确)
评估:RLS 策略工作正常。
─────────────────────────────────────────────────────────
uploads(公开存储桶)
─────────────────────────────────────────────────────────
状态:🟠 P1 - 敏感文件暴露
找到文件:3,891
检测到的敏感文件:
├── 🔴 invoice-2025-001.pdf - 包含财务数据
├── 🔴 contract-signed.pdf - 法律文件
├── 🔴 id-verification.jpg - 个人身份证照片!
├── ⚠️ database-export.csv - 可能的数据导出
└── ⚠️ config.json - 配置文件
文件类型分布:
├── PDF:1,234 (31%)
├── 图片:2,100 (54%)
├── 文档:450 (12%)
└── 其他:107 (3%)
评估:存储桶包含不应公开的敏感文件!
─────────────────────────────────────────────────────────
backups(公开 - 严重)
─────────────────────────────────────────────────────────
状态:🔴 P0 - 关键数据暴露
找到文件:45
暴露的文件:
├── 🔴 db-backup-2025-01-30.sql (125MB) - 数据库备份!
├── 🔴 db-backup-2025-01-29.sql (124MB) - 数据库备份!
├── 🔴 users-export.csv (2.3MB) - 用户数据导出!
├── 🔴 secrets.env (1KB) - 环境变量密钥!
└── 🔴 .env.production (1KB) - 生产环境密钥!
示例内容(secrets.env):
┌─────────────────────────────────────────────────────────┐
│ STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxx │
│ DATABASE_URL=postgresql://postgres:xxx@... │
│ JWT_SECRET=super-secret-jwt-key │
└─────────────────────────────────────────────────────────┘
⚠️ 需要立即采取行动:
1. 立即将存储桶设为私有
2. 轮换所有暴露的密钥
3. 从公共访问中删除备份文件
4. 在日志中审计未经授权的访问
─────────────────────────────────────────────────────────
temp(私有存储桶)
─────────────────────────────────────────────────────────
状态:✅ 受到适当保护
找到文件:0(通过匿名密钥)
评估:访问权限被正确限制。
─────────────────────────────────────────────────────────
总结
─────────────────────────────────────────────────────────
P0 严重:1 个存储桶(backups - 数据库转储和密钥暴露)
P1 高危:1 个存储桶(uploads - 公开存储桶中的敏感文档)
受保护:2 个存储桶(documents, temp)
预期情况:1 个存储桶(avatars)
可访问文件总数:5,183
暴露的敏感文件:52
暴露的密钥文件:3
立即行动:
1. 🔴 删除或将 'backups' 存储桶设为私有
2. 🔴 轮换 Stripe 密钥、数据库密码、JWT 密钥
3. 🟠 将敏感文件从 'uploads' 移动到私有存储桶
4. 审查所有 52 个敏感文件的暴露影响
═══════════════════════════════════════════════════════════
此技能通过以下方式识别敏感文件:
| 模式 | 风险等级 | 类型 |
|---|---|---|
*.sql, backup* | P0 | 数据库转储 |
.env*, *secrets* | P0 | 密钥文件 |
*password*, *credential* | P0 | 凭证 |
*invoice*, *payment* | P1 | 财务 |
*contract*, *agreement* | P1 | 法律 |
*id*, *passport*, *license* | P1 | 身份 |
*export*, *dump* | P1 | 数据导出 |
对于可访问的文件,此技能会采样内容以检测:
sk_live_、pk_test_ 等模式){
"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. 轮换 Stripe 密钥
# Stripe 仪表板 → 开发者 → API 密钥 → 轮换密钥
# 2. 更改数据库密码
# Supabase 仪表板 → 设置 → 数据库 → 重置密码
# 3. 重新生成 JWT 密钥
# Supabase 仪表板 → 设置 → API → 重新生成 JWT 密钥
# 4. 更新应用程序环境变量
# 使用新密钥重新部署
-- 将存储桶设为私有
UPDATE storage.buckets
SET public = false
WHERE name = 'backups';
-- 删除敏感文件或移动到安全位置
DELETE FROM storage.objects
WHERE bucket_id = 'backups';
-- 添加 RLS 以限制访问
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"]
}
}
# === 存储文件访问测试 ===
# 列出 backups 存储桶中的文件
curl -s "$SUPABASE_URL/storage/v1/object/list/backups" \
-H "apikey: $ANON_KEY"
# 直接访问公共文件(如果可访问则为 P0)
curl -I "https://abc123def.supabase.co/storage/v1/object/public/backups/secrets.env"
# 下载暴露的备份(用于证据 - 注意文件大小)
# 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 — 生成完整报告每周安装次数
86
代码仓库
GitHub 星标数
32
首次出现
2026年1月31日
安全审计
安装于
claude-code70
codex63
opencode62
gemini-cli59
cursor54
github-copilot54
🔴 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 bucket tested- Log to
.sb-pentest-audit.logBEFORE and AFTER each file access 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 actual file access in storage buckets to verify permissions.
The skill attempts to:
Important: This is READ-ONLY. No files are modified or deleted.
| Bucket Type | Tests Performed |
|---|---|
| Public | Direct URL access, listing, metadata |
| Private | API listing with anon key, authenticated access |
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
═══════════════════════════════════════════════════════════
The skill identifies sensitive files by:
| Pattern | Risk | Type |
|---|---|---|
*.sql, backup* | P0 | Database dumps |
.env*, *secrets* | P0 | Secret files |
*password*, *credential* | P0 | Credentials |
*invoice*, |
For accessible files, the skill samples content for:
sk_live_, pk_test_){
"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]
);
❌ Problem: Cannot list files in private bucket ✅ Solution: This is correct behavior. RLS is working.
❌ Problem: Large number of files to scan ✅ Solution: Use sampling mode for large buckets.
❌ Problem: File download fails ✅ Solution: May be RLS restriction or network issue.
⚠️ 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.jsonThis 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:
{
"storage_access": {
"timestamp": "...",
"buckets_tested": 5,
"findings": [ ... ],
"summary": { "total_files_accessible": 5183, ... }
}
}
Log to.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
If files don't exist , create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
📁 Evidence Directory: .sb-pentest-evidence/04-storage-audit/buckets/
| File | Content |
|---|---|
buckets/[name]/file-list.json | Files found in bucket |
buckets/[name]/sensitive-files.json | Sensitive files detected |
buckets/[name]/sample-contents/ | Redacted content samples |
{
"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"]
}
}
# === 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 — List buckets firstsupabase-audit-buckets-public — Focus on public access issuessupabase-report — Generate full reportWeekly Installs
86
Repository
GitHub Stars
32
First Seen
Jan 31, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykFail
Installed on
claude-code70
codex63
opencode62
gemini-cli59
cursor54
github-copilot54
Supabase Postgres 最佳实践指南 - 8大类别性能优化规则与SQL示例
78,800 周安装
*payment*| P1 |
| Financial |
*contract*, *agreement* | P1 | Legal |
*id*, *passport*, *license* | P1 | Identity |
*export*, *dump* | P1 | Data exports |