supabase-extract-anon-key について
クライアント側コードから Supabase の anon 公開 API キーを抽出する監査スキルです。一般的なコードや環境変数のパターンを検索し、JWT の内容を検証して結果を逐次記録します。
主な機能
- 01クライアント側コードから anon キーを検索
- 02クライアント初期化と環境変数のパターンを確認
- 03JWT 形式、ロール、プロジェクト参照を検証
- 04キーの出所を記録し証拠を保存
- 05コンテキストと監査ログを逐次更新
活用シーン
- 01Supabase API 監査に必要な anon キーを取得
- 02クライアントコードに誤った種類のキーが露出していないか確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-extract-anon-keyインストール後、Claude Code で/supabase-extract-anon-keyを入力して読み込まれたか確認します。
詳細
Supabase Anon Key の抽出
🔴 重大:コンテキストファイルの段階的な更新が必須です
コンテキストファイルには、最後にまとめてではなく、作業を進めながら必ず書き込んでください。
- 発見のたびに、直ちに
.sb-pentest-context.jsonに書き込んでください- 各アクションの前後に
.sb-pentest-audit.logに記録してください- スキルの完了までファイルの更新を待たないでください
- スキルがクラッシュしたり中断されたりした場合でも、それまでの調査結果がすべて保存されている必要があります
これは任意ではありません。段階的に書き込まないことは重大なエラーです。
このスキルは、クライアント側のコードから Supabase の匿名(公開)API キーを抽出します。
このスキルを使用するタイミング
- Supabase URL の抽出後、テスト用の API キーを取得するとき
- anon キーのみが公開されており、service キーは公開されていないことを確認するとき
- 認証が必要な API 監査スキルを実行する前
前提条件
- Supabase URL が抽出済みであること(または
supabase-extract-urlを自動的に呼び出すこと) - 対象アプリケーションにアクセスできること
Anon キーについて
anon キー(公開キーとも呼ばれます)は次のとおりです。
- ✅ クライアント側のコードに含まれていることが想定されています
- ✅ RLS(行レベルセキュリティ)が適切に設定されていれば安全です
- ⚠️ RLS が未設定、または誤って設定されている場合はリスクがあります
- ❌ service_role キーとは異なります(クライアント側のコードに含めては絶対にいけません)
キーの形式
Supabase の anon キーは JWT です。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFiYzEyMyIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9.xxxx
キーの特徴:
eyJで始まります({"alg":を Base64 エンコードしたもの)- ペイロードに
"role":"anon"が含まれます "ref"クレームにプロジェクトの参照情報が含まれます
抽出パターン
このスキルでは、次のパターンを検索します。
1. キーの直接代入
const SUPABASE_KEY = 'eyJhbGci...'
const SUPABASE_ANON_KEY = 'eyJhbGci...'
2. クライアントの初期化
createClient(url, 'eyJhbGci...')
createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
3. 環境変数のパターン
NEXT_PUBLIC_SUPABASE_ANON_KEY
VITE_SUPABASE_ANON_KEY
REACT_APP_SUPABASE_KEY
SUPABASE_KEY
使用方法
基本的な抽出
Extract Supabase anon key from https://myapp.example.com
URL がすでにわかっている場合
Extract anon key for project abc123def
出力形式
═══════════════════════════════════════════════════════════
ANON KEY EXTRACTED
═══════════════════════════════════════════════════════════
Key Type: anon (public)
Severity: ℹ️ Expected (verify RLS configuration)
Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJz
dXBhYmFzZSIsInJlZiI6ImFiYzEyM2RlZiIsInJvbGUiOiJhbm
9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9
.xxxxxxxxxxxxx
Decoded Payload:
├── iss: supabase
├── ref: abc123def
├── role: anon
├── iat: 2021-12-20T00:00:00Z
└── exp: 2031-12-20T00:00:00Z
Found in:
└── /static/js/main.js (line 1253)
createClient('https://abc123def.supabase.co', 'eyJhbGci...')
Next Steps:
├── Run supabase-audit-rls to test if RLS protects your data
├── Run supabase-audit-tables-read to see what's accessible
└── Run supabase-extract-service-key to check for critical leaks
Context updated: .sb-pentest-context.json
═══════════════════════════════════════════════════════════
キーの検証
このスキルでは、抽出したキーを検証します。
Validation:
├── Format: ✅ Valid JWT structure
├── Decode: ✅ Payload readable
├── Role: ✅ Confirmed "anon" role
├── Project: ✅ Matches extracted URL (abc123def)
└── Expiry: ✅ Not expired (expires 2031-12-20)
複数のキー
複数のキーが見つかった場合:
═══════════════════════════════════════════════════════════
MULTIPLE KEYS FOUND
═══════════════════════════════════════════════════════════
⚠️ 2 potential Supabase keys detected
1. Anon Key (confirmed)
└── Role: anon, Project: abc123def
2. Unknown Key
└── Role: service_role ⚠️ SEE supabase-extract-service-key
This may be a CRITICAL security issue!
═══════════════════════════════════════════════════════════
コンテキスト出力
.sb-pentest-context.json に保存されます。
{
"supabase": {
"anon_key": "eyJhbGci...",
"anon_key_decoded": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": 1640000000,
"exp": 1955360000
},
"anon_key_sources": [
{
"file": "/static/js/main.js",
"line": 1253
}
]
}
}
セキュリティ評価
| 検出事項 | 重大度 | 説明 |
|---|---|---|
| クライアント側の anon キー | ℹ️ 情報 | 想定される状態ですが、RLS をテストしてください |
| 期限切れの anon キー | ⚠️ P2 | キーをローテーションしてください |
| 複数の anon キー | ⚠️ P2 | キーのローテーションに問題がある可能性があります |
ロールが "anon" ではない | 🔴 P0 | 誤った種類のキーが公開されています! |
よくある問題
❌ 問題: キーが見つかったものの、デコードできない ✅ 解決策: 難読化または分割されている可能性があります。次を試してください。
Extract anon key with deobfuscation from https://myapp.example.com
❌ 問題: キーが URL のプロジェクトと一致しない ✅ 解決策: アプリが複数の Supabase プロジェクトを使用している可能性があります。両方のキーが記録されます。
❌ 問題: Supabase が検出されたのに、キーが見つからない ✅ 解決策: キーが実行時に取得されている可能性があります。ネットワークリクエストを確認してください。
Monitor network for anon key on https://myapp.example.com
ベストプラクティスに関する注意
このレポートを読む開発者向け:
- クライアント側に anon キーがあるのは通常のことです — そのように設計されています
- RLS は非常に重要です — anon キーのセキュリティは RLS に依存します
- クライアント側で service_role を使用しないでください — 代わりに Edge Functions を使用してください
- キーを定期的にローテーションしてください — Supabase Dashboard で実行できます
必須:コンテキストファイルの段階的な更新
⚠️ このスキルでは、最後にまとめてではなく、実行中に追跡ファイルを段階的に更新する必要があります。
重要なルール:作業を進めながら書き込む
すべての書き込みを最後にまとめるのはやめてください。代わりに、次の手順で進めます。
- アクションを開始する前に →
.sb-pentest-audit.logにアクションを記録します - 発見のたびに → 直ちに
.sb-pentest-context.jsonを更新します - 重要な手順のたびに →
.sb-pentest-audit.logに完了を記録します
これにより、スキルが中断、クラッシュ、またはタイムアウトした場合でも、それまでの調査結果がすべて保持されます。
必須のアクション(段階的に実施)
-
抽出したデータを
.sb-pentest-context.jsonに更新します。{ "supabase": { "anon_key": "eyJhbGci...", "anon_key_decoded": { ... }, "anon_key_sources": [ ... ] } } -
.sb-pentest-audit.logに記録します。[TIMESTAMP] [supabase-extract-anon-key] [START] Beginning anon key extraction [TIMESTAMP] [supabase-extract-anon-key] [SUCCESS] Anon key extracted [TIMESTAMP] [supabase-extract-anon-key] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
ファイルが存在しない場合は、書き込み前に作成します。
コンテキストファイルを更新しないことは許容されません。
必須:証拠の収集
📁 証拠ディレクトリ: .sb-pentest-evidence/02-extraction/
作成する証拠ファイル
| ファイル | 内容 |
|---|---|
extracted-anon-key.json | デコードされた JWT ペイロードを含む anon キー |
証拠の形式
{
"evidence_id": "EXT-ANON-001",
"timestamp": "2025-01-31T10:07:00Z",
"category": "extraction",
"type": "anon_key",
"severity": "info",
"key_data": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"key_suffix": "...xxxx",
"full_key_length": 256
},
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": "2021-12-20T00:00:00Z",
"exp": "2031-12-20T00:00:00Z"
},
"source": {
"file": "/static/js/main.js",
"line": 1253,
"context": "createClient('https://abc123def.supabase.co', 'eyJhbGci...')"
},
"validation": {
"format_valid": true,
"role_confirmed": "anon",
"project_matches": true,
"expired": false
}
}
関連スキル
supabase-extract-url— まず URL を取得します(必要に応じて自動的に呼び出されます)supabase-extract-service-key— 重大な service キーの漏えいを確認しますsupabase-audit-rls— RLS がデータを保護しているかテストしますsupabase-audit-tables-read— このキーでアクセスできるデータを確認します