mcpField
S
supabase-extract-jwt

supabase-extract-jwt

github.com/yoanbernabeuセキュリティ71473 回インストール39 週間前に更新
リポジトリ

supabase-extract-jwt について

クライアント側コードに含まれるSupabase関連JWTを検出・分析するセキュリティスキルです。トークンのクレームや保存先の参照を調べ、露出したキー、ハードコードされたユーザートークン、認証情報の把握に役立ちます。

主な機能

  1. 01クライアントコード内のJWTとAPIキーの検出
  2. 02トークンクレームと有効期限の分析
  3. 03ハードコードされたユーザートークンと個人情報の検出
  4. 04JWTの保存先参照の特定
  5. 05検出結果と抽出証拠の保存

活用シーン

  1. 01クライアントコードのservice roleキー露出確認
  2. 02ハードコードされたユーザートークンの調査
  3. 03トークンクレームと有効期限の確認
  4. 04認証関連コードのパターン把握

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-extract-jwt

インストール後、Claude Code で/supabase-extract-jwtを入力して読み込まれたか確認します。

詳細

Supabase JWT の抽出

🔴 重大:ファイルの段階的な更新が必須です

コンテキストファイルには、最後だけでなく作業中に随時書き込む必要があります。

  • 発見するたびに、直ちに .sb-pentest-context.json に書き込んでください
  • 各アクションの前後に .sb-pentest-audit.log に記録してください
  • スキルが完了するまでファイルの更新を待たないでください
  • スキルがクラッシュしたり中断されたりしても、それまでのすべての調査結果がすでに保存されている必要があります

これは任意ではありません。段階的な書き込みを怠ると重大なエラーになります。

このスキルは、クライアント側のコードに関連する Supabase の JSON Web Token(JWT)を抽出して分析します。

このスキルを使用する場面

  • クライアントコードに公開されているすべての JWT トークンを見つける場合
  • トークンのクレームと有効期限を分析する場合
  • ハードコードされたユーザートークン(セキュリティ上の問題)を検出する場合
  • 認証フローを把握する場合

前提条件

  • 対象のアプリケーションにアクセスできること
  • Supabase の検出が完了していること(必要に応じて自動的に実行されます)

Supabase の JWT の種類

種類用途クライアントへの公開
Anon KeyAPI 認証✅ 想定どおり
Service Role Key管理者アクセス❌ 決して公開しない
Access Tokenユーザーセッション⚠️ 動的な場合のみ
Refresh Tokenトークンの更新⚠️ 動的な場合のみ

検出パターン

1. API キー(静的)
// Supabase API keys are JWTs
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
2. ハードコードされたユーザートークン(問題あり)
// ❌ Should never be hardcoded
const userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIn0...'
3. ストレージキーのパターン
// Code referencing where JWTs are stored
localStorage.getItem('supabase.auth.token')
localStorage.getItem('sb-abc123-auth-token')
sessionStorage.getItem('supabase_session')

使用方法

基本的な抽出
Extract JWTs from https://myapp.example.com
クレーム分析を含める場合
Extract and analyze all JWTs from https://myapp.example.com

出力形式

═══════════════════════════════════════════════════════════
 JWT EXTRACTION RESULTS
═══════════════════════════════════════════════════════════

 Found: 3 JWTs

 ─────────────────────────────────────────────────────────
 JWT #1: Supabase Anon Key
 ─────────────────────────────────────────────────────────
 Type: API Key (anon)
 Status: ✅ Expected in client code

 Header:
 ├── alg: HS256
 └── typ: JWT

 Payload:
 ├── iss: supabase
 ├── ref: abc123def
 ├── role: anon
 ├── iat: 2021-12-20T00:00:00Z
 └── exp: 2031-12-20T00:00:00Z

 Location: /static/js/main.js:1247

 ─────────────────────────────────────────────────────────
 JWT #2: Hardcoded User Token ⚠️
 ─────────────────────────────────────────────────────────
 Type: User Access Token
 Status: ⚠️ P1 - Should not be hardcoded

 Header:
 ├── alg: HS256
 └── typ: JWT

 Payload:
 ├── sub: 12345678-1234-1234-1234-123456789012
 ├── email: [email protected]
 ├── role: authenticated
 ├── iat: 2025-01-15T10:00:00Z
 └── exp: 2025-01-15T11:00:00Z (EXPIRED)

 Location: /static/js/debug.js:45

 Risk: This token may belong to a real user account.
       Even if expired, it reveals user information.

 ─────────────────────────────────────────────────────────
 JWT #3: Storage Reference
 ─────────────────────────────────────────────────────────
 Type: Storage Key Pattern
 Status: ℹ️ Informational

 Pattern: localStorage.getItem('sb-abc123def-auth-token')
 Location: /static/js/auth.js:89

 Note: This is the expected storage key for user sessions.
       Actual token value is set at runtime.

═══════════════════════════════════════════════════════════

JWT クレームの分析

このスキルは主要なクレームを特定します。

標準クレーム
クレーム説明セキュリティへの影響
subユーザー ID特定のユーザーを識別します
emailユーザーのメールアドレスハードコードされている場合、個人情報(PII)が漏えいします
role権限レベルservice_role は重大な問題です
exp有効期限期限切れのトークンはリスクが低くなります
iat発行時刻作成時期を示します
Supabase 固有のクレーム
クレーム説明
refプロジェクト参照
iss「supabase」である必要があります
aal認証器保証レベル
amr使用された認証方式

セキュリティ上の検出事項

P0 - 重大
🔴 Service role key exposed (role: service_role)
   → Immediate key rotation required
P1 - 高
🟠 User token hardcoded with PII (email, sub visible)
   → Remove from code, may need to notify user
P2 - 中
🟡 Expired test token in code
   → Clean up, potential information disclosure

コンテキスト出力

.sb-pentest-context.json に保存されます。

{
  "jwts": {
    "found": 3,
    "api_keys": [
      {
        "type": "anon",
        "project_ref": "abc123def",
        "location": "/static/js/main.js:1247"
      }
    ],
    "user_tokens": [
      {
        "type": "access_token",
        "hardcoded": true,
        "severity": "P1",
        "claims": {
          "sub": "12345678-1234-1234-1234-123456789012",
          "email": "[email protected]",
          "expired": true
        },
        "location": "/static/js/debug.js:45"
      }
    ],
    "storage_patterns": [
      {
        "pattern": "sb-abc123def-auth-token",
        "storage": "localStorage",
        "location": "/static/js/auth.js:89"
      }
    ]
  }
}

よくある問題

❌ 問題: JWT が途中で切れているように見える
✅ 解決策: 複数行にまたがっている可能性があります。このスキルは再結合を試みます。

❌ 問題: JWT をデコードできない
✅ 解決策: 暗号化されている(JWE)か、独自の形式である可能性があります。デコード不能として記録されます。

❌ 問題: 誤検出が多い
✅ 解決策: JWT のように見える Base64 文字列が原因です。このスキルは構造を検証します。

ハードコードされたトークンの修正

修正前(誤り)
// ❌ Never hardcode user tokens
const adminToken = 'eyJhbGciOiJIUzI1NiI...'
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${adminToken}` }
})
修正後(正しい例)
// ✅ Get token from Supabase session
const { data: { session } } = await supabase.auth.getSession()
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${session.access_token}` }
})

必須:コンテキストファイルの段階的な更新

⚠️ このスキルでは、実行の最後だけでなく、実行中に追跡ファイルを段階的に更新する必要があります。

重要なルール:作業中に書き込む

すべての書き込みを最後にまとめて行わないでください。代わりに、次の手順に従ってください。

  1. アクションを開始する前に → アクションを .sb-pentest-audit.log に記録します
  2. 発見するたびに → 直ちに .sb-pentest-context.json を更新します
  3. 重要な手順が完了するたびに → 完了を .sb-pentest-audit.log に記録します

これにより、スキルが中断されたり、クラッシュしたり、タイムアウトしたりしても、その時点までのすべての調査結果を保持できます。

必須アクション(段階的に実施)
  1. 抽出したデータで .sb-pentest-context.json を更新します。

    {
      "jwts": {
        "found": 3,
        "api_keys": [ ... ],
        "user_tokens": [ ... ],
        "storage_patterns": [ ... ]
      }
    }
    
  2. .sb-pentest-audit.log に記録します。

    [TIMESTAMP] [supabase-extract-jwt] [START] Beginning JWT extraction
    [TIMESTAMP] [supabase-extract-jwt] [SUCCESS] Found 3 JWTs
    [TIMESTAMP] [supabase-extract-jwt] [CONTEXT_UPDATED] .sb-pentest-context.json updated
    
  3. ファイルが存在しない場合は、書き込む前に作成します。

コンテキストファイルを更新しないことは許容されません。

必須:証拠の収集

📁 証拠ディレクトリ: .sb-pentest-evidence/02-extraction/

作成する証拠ファイル
ファイル内容
extracted-jwts.json分析結果を含む、見つかったすべての JWT
証拠の形式
{
  "evidence_id": "EXT-JWT-001",
  "timestamp": "2025-01-31T10:08:00Z",
  "category": "extraction",
  "type": "jwt_extraction",

  "jwts_found": [
    {
      "type": "anon_key",
      "severity": "info",
      "location": "/static/js/main.js:1247",
      "decoded_payload": {
        "iss": "supabase",
        "ref": "abc123def",
        "role": "anon"
      }
    },
    {
      "type": "hardcoded_user_token",
      "severity": "P1",
      "location": "/static/js/debug.js:45",
      "decoded_payload": {
        "sub": "[REDACTED]",
        "email": "[REDACTED]@example.com",
        "role": "authenticated",
        "exp": "2025-01-15T11:00:00Z"
      },
      "expired": true,
      "issue": "Hardcoded user token with PII"
    }
  ],

  "storage_patterns_found": [
    {
      "pattern": "localStorage.getItem('sb-abc123def-auth-token')",
      "location": "/static/js/auth.js:89"
    }
  ]
}

関連スキル

  • supabase-extract-anon-key — anon key を特定して抽出します
  • supabase-extract-service-key — service key の有無を確認します(重要)
  • supabase-audit-auth-config — 認証設定を分析します

コメント