supabase-extract-jwt

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Supabase JWT Extraction

Supabase JWT 提取

🔴 CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED
You MUST write to context files AS YOU GO, not just at the end.
  • Write to
    .sb-pentest-context.json
    IMMEDIATELY after each discovery
  • Log to
    .sb-pentest-audit.log
    BEFORE and AFTER each action
  • 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 extracts and analyzes JSON Web Tokens (JWTs) related to Supabase from client-side code.
🔴 关键:需逐步更新文件
你必须逐步写入上下文文件,而不是只在最后写入。
  • 每次发现后立即写入
    .sb-pentest-context.json
  • 每次操作前后都要记录到
    .sb-pentest-audit.log
  • 不要等到技能完成后再更新文件
  • 如果技能崩溃或被中断,所有已有的发现必须已保存
这不是可选要求。不逐步写入属于严重错误。
本技能从客户端代码中提取并分析与Supabase相关的JSON Web Token(JWT)。

When to Use This Skill

何时使用本技能

  • To find all JWT tokens exposed in client code
  • To analyze token claims and expiration
  • To detect hardcoded user tokens (security issue)
  • To understand the authentication flow
  • 查找客户端代码中暴露的所有JWT令牌
  • 分析令牌声明和过期时间
  • 检测硬编码的用户令牌(安全问题)
  • 理解认证流程

Prerequisites

前置条件

  • Target application accessible
  • Supabase detection completed (auto-invokes if needed)
  • 可访问目标应用
  • 已完成Supabase检测(如未完成会自动触发)

Types of JWTs in Supabase

Supabase中的JWT类型

TypePurposeClient Exposure
Anon KeyAPI authentication✅ Expected
Service Role KeyAdmin access❌ Never
Access TokenUser session⚠️ Dynamic only
Refresh TokenToken renewal⚠️ Dynamic only
类型用途客户端暴露情况
Anon KeyAPI认证✅ 正常情况
Service Role Key管理员权限❌ 绝不允许
Access Token用户会话⚠️ 仅动态生成
Refresh Token令牌续期⚠️ 仅动态生成

Detection Patterns

检测模式

1. API Keys (Static)

1. API密钥(静态)

javascript
// Supabase API keys are JWTs
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
javascript
// Supabase API密钥属于JWT
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'

2. Hardcoded User Tokens (Problem)

2. 硬编码用户令牌(问题)

javascript
// ❌ Should never be hardcoded
const userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIn0...'
javascript
// ❌ 绝不应该硬编码
const userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIn0...'

3. Storage Key Patterns

3. 存储键模式

javascript
// Code referencing where JWTs are stored
localStorage.getItem('supabase.auth.token')
localStorage.getItem('sb-abc123-auth-token')
sessionStorage.getItem('supabase_session')
javascript
// 引用JWT存储位置的代码
localStorage.getItem('supabase.auth.token')
localStorage.getItem('sb-abc123-auth-token')
sessionStorage.getItem('supabase_session')

Usage

使用方法

Basic Extraction

基础提取

Extract JWTs from https://myapp.example.com
从 https://myapp.example.com 提取JWT

With Claim Analysis

带声明分析

Extract and analyze all JWTs from https://myapp.example.com
从 https://myapp.example.com 提取并分析所有JWT

Output Format

输出格式

═══════════════════════════════════════════════════════════
 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: developer@company.com
 ├── 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 提取结果
═══════════════════════════════════════════════════════════

 找到:3个JWT

 ─────────────────────────────────────────────────────────
 JWT #1: Supabase Anon Key
 ─────────────────────────────────────────────────────────
 类型:API密钥(anon)
 状态:✅ 客户端代码中正常存在

 头部:
 ├── alg: HS256
 └── typ: JWT

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

 位置:/static/js/main.js:1247

 ─────────────────────────────────────────────────────────
 JWT #2: 硬编码用户令牌 ⚠️
 ─────────────────────────────────────────────────────────
 类型:用户访问令牌
 状态:⚠️ P1 - 不应硬编码

 头部:
 ├── alg: HS256
 └── typ: JWT

 负载:
 ├── sub: 12345678-1234-1234-1234-123456789012
 ├── email: developer@company.com
 ├── role: authenticated
 ├── iat: 2025-01-15T10:00:00Z
 └── exp: 2025-01-15T11:00:00Z(已过期)

 位置:/static/js/debug.js:45

 风险:该令牌可能属于真实用户账户。
       即使已过期,仍会泄露用户信息。

 ─────────────────────────────────────────────────────────
 JWT #3: 存储引用
 ─────────────────────────────────────────────────────────
 类型:存储键模式
 状态:ℹ️ 信息性

 模式:localStorage.getItem('sb-abc123def-auth-token')
 位置:/static/js/auth.js:89

 说明:这是用户会话的预期存储键。
       实际令牌值在运行时设置。

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

JWT Claim Analysis

JWT声明分析

The skill identifies key claims:
本技能会识别关键声明:

Standard Claims

标准声明

ClaimDescriptionSecurity Impact
sub
User IDIdentifies specific user
email
User emailPII exposure if hardcoded
role
Permission level
service_role
is critical
exp
ExpirationExpired tokens less risky
iat
Issued atIndicates when created
声明描述安全影响
sub
用户ID识别特定用户
email
用户邮箱硬编码时会泄露个人身份信息(PII)
role
权限级别
service_role
属于关键权限
exp
过期时间过期令牌风险较低
iat
签发时间指示令牌创建时间

Supabase-Specific Claims

Supabase特定声明

ClaimDescription
ref
Project reference
iss
Should be "supabase"
aal
Authenticator assurance level
amr
Authentication methods used
声明描述
ref
项目引用
iss
应为 "supabase"
aal
认证器保障级别
amr
使用的认证方法

Security Findings

安全发现

P0 - Critical

P0 - 严重

🔴 Service role key exposed (role: service_role)
   → Immediate key rotation required
🔴 暴露服务角色密钥(role: service_role)
   → 需立即轮换密钥

P1 - High

P1 - 高

🟠 User token hardcoded with PII (email, sub visible)
   → Remove from code, may need to notify user
🟠 硬编码包含个人身份信息的用户令牌(可见email、sub)
   → 从代码中移除,可能需要通知用户

P2 - Medium

P2 - 中

🟡 Expired test token in code
   → Clean up, potential information disclosure
🟡 代码中存在过期测试令牌
   → 清理代码,存在潜在信息泄露风险

Context Output

上下文输出

Saved to
.sb-pentest-context.json
:
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": "developer@company.com",
          "expired": true
        },
        "location": "/static/js/debug.js:45"
      }
    ],
    "storage_patterns": [
      {
        "pattern": "sb-abc123def-auth-token",
        "storage": "localStorage",
        "location": "/static/js/auth.js:89"
      }
    ]
  }
}
保存至
.sb-pentest-context.json
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": "developer@company.com",
          "expired": true
        },
        "location": "/static/js/debug.js:45"
      }
    ],
    "storage_patterns": [
      {
        "pattern": "sb-abc123def-auth-token",
        "storage": "localStorage",
        "location": "/static/js/auth.js:89"
      }
    ]
  }
}

Common Issues

常见问题

Problem: JWT appears truncated ✅ Solution: May span multiple lines. The skill attempts to reassemble.
Problem: JWT won't decode ✅ Solution: May be encrypted (JWE) or custom format. Noted as undecodable.
Problem: Many false positives ✅ Solution: Base64 strings that look like JWTs. Skill validates structure.
问题:JWT显示被截断解决方案:可能跨多行。本技能会尝试重组。
问题:JWT无法解码解决方案:可能是加密格式(JWE)或自定义格式。会标记为无法解码。
问题:大量误报解决方案:类似JWT的Base64字符串。本技能会验证结构。

Remediation for Hardcoded Tokens

硬编码令牌的修复方案

Before (Wrong)

之前(错误)

javascript
// ❌ Never hardcode user tokens
const adminToken = 'eyJhbGciOiJIUzI1NiI...'
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${adminToken}` }
})
javascript
// ❌ 绝不硬编码用户令牌
const adminToken = 'eyJhbGciOiJIUzI1NiI...'
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${adminToken}` }
})

After (Correct)

之后(正确)

javascript
// ✅ Get token from Supabase session
const { data: { session } } = await supabase.auth.getSession()
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${session.access_token}` }
})
javascript
// ✅ 从Supabase会话获取令牌
const { data: { session } } = await supabase.auth.getSession()
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${session.access_token}` }
})

MANDATORY: Progressive Context File Updates

强制要求:逐步更新上下文文件

⚠️ This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.
⚠️ 本技能必须在执行过程中逐步更新跟踪文件,而不是只在最后更新。

Critical Rule: Write As You Go

关键规则:边执行边写入

DO NOT batch all writes at the end. Instead:
  1. Before starting any action → Log the action to
    .sb-pentest-audit.log
  2. After each discovery → Immediately update
    .sb-pentest-context.json
  3. After each significant step → Log completion to
    .sb-pentest-audit.log
This ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
不要批量在最后写入。而是:
  1. 开始任何操作前 → 将操作记录到
    .sb-pentest-audit.log
  2. 每次发现后 → 立即更新
    .sb-pentest-context.json
  3. 完成每个重要步骤后 → 将完成情况记录到
    .sb-pentest-audit.log
这样可以确保如果技能被中断、崩溃或超时,所有截至该点的发现都已保存。

Required Actions (Progressive)

需执行的逐步操作

  1. Update
    .sb-pentest-context.json
    with extracted data:
    json
    {
      "jwts": {
        "found": 3,
        "api_keys": [ ... ],
        "user_tokens": [ ... ],
        "storage_patterns": [ ... ]
      }
    }
  2. Log to
    .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. If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
  1. 更新
    .sb-pentest-context.json
    并写入提取的数据:
    json
    {
      "jwts": {
        "found": 3,
        "api_keys": [ ... ],
        "user_tokens": [ ... ],
        "storage_patterns": [ ... ]
      }
    }
  2. 记录到
    .sb-pentest-audit.log
    [时间戳] [supabase-extract-jwt] [开始] 开始JWT提取
    [时间戳] [supabase-extract-jwt] [成功] 找到3个JWT
    [时间戳] [supabase-extract-jwt] [上下文已更新] .sb-pentest-context.json已更新
  3. 如果文件不存在,在写入前创建。
不更新上下文文件是不被接受的。

MANDATORY: Evidence Collection

强制要求:证据收集

📁 Evidence Directory:
.sb-pentest-evidence/02-extraction/
📁 证据目录:
.sb-pentest-evidence/02-extraction/

Evidence Files to Create

需创建的证据文件

FileContent
extracted-jwts.json
All JWTs found with analysis
文件内容
extracted-jwts.json
所有找到的JWT及分析结果

Evidence Format

证据格式

json
{
  "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"
    }
  ]
}
json
{
  "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": "[已脱敏]",
        "email": "[已脱敏]@example.com",
        "role": "authenticated",
        "exp": "2025-01-15T11:00:00Z"
      },
      "expired": true,
      "issue": "硬编码包含个人身份信息的用户令牌"
    }
  ],

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

Related Skills

相关技能

  • supabase-extract-anon-key
    — Specifically extracts the anon key
  • supabase-extract-service-key
    — Checks for service key (critical)
  • supabase-audit-auth-config
    — Analyzes auth configuration
  • supabase-extract-anon-key
    — 专门提取anon密钥
  • supabase-extract-service-key
    — 检查服务密钥(关键)
  • supabase-audit-auth-config
    — 分析认证配置