supabase-audit-buckets-read について
Supabase のセキュリティ監査向けスキルで、Storage バケット内のファイルアクセスを試して権限を検証します。一覧、メタデータ、サンプルのダウンロード、公開 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 キーが利用可能
動作の仕組み
このスキルでは、次のことを試みます。
- 各バケット内のファイルを一覧表示する
- ファイルのメタデータを読み取る
- サンプルファイルをダウンロードする(コンテンツタイプの検証用)
- パブリック URL へのアクセスを確認する
重要: これは読み取り専用です。ファイルの変更や削除は行いません。
テスト方法
| バケットの種類 | 実施するテスト |
|---|---|
| パブリック | 直接 URL アクセス、一覧表示、メタデータ |
| プライベート | Anon キーによる 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— 完全なレポートを生成します