supabase-extract-jwt
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSupabase JWT Extraction
Supabase JWT 提取
🔴 CRITICAL: PROGRESSIVE FILE UPDATES REQUIREDYou MUST write to context files AS YOU GO, not just at the end.
- Write to
IMMEDIATELY after each discovery.sb-pentest-context.json- Log to
BEFORE and AFTER each action.sb-pentest-audit.log- 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类型
| Type | Purpose | Client Exposure |
|---|---|---|
| Anon Key | API authentication | ✅ Expected |
| Service Role Key | Admin access | ❌ Never |
| Access Token | User session | ⚠️ Dynamic only |
| Refresh Token | Token renewal | ⚠️ Dynamic only |
| 类型 | 用途 | 客户端暴露情况 |
|---|---|---|
| Anon Key | API认证 | ✅ 正常情况 |
| 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 提取JWTWith Claim Analysis
带声明分析
Extract and analyze all JWTs from https://myapp.example.com从 https://myapp.example.com 提取并分析所有JWTOutput 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
标准声明
| Claim | Description | Security Impact |
|---|---|---|
| User ID | Identifies specific user |
| User email | PII exposure if hardcoded |
| Permission level | |
| Expiration | Expired tokens less risky |
| Issued at | Indicates when created |
| 声明 | 描述 | 安全影响 |
|---|---|---|
| 用户ID | 识别特定用户 |
| 用户邮箱 | 硬编码时会泄露个人身份信息(PII) |
| 权限级别 | |
| 过期时间 | 过期令牌风险较低 |
| 签发时间 | 指示令牌创建时间 |
Supabase-Specific Claims
Supabase特定声明
| Claim | Description |
|---|---|
| Project reference |
| Should be "supabase" |
| Authenticator assurance level |
| Authentication methods used |
| 声明 | 描述 |
|---|---|
| 项目引用 |
| 应为 "supabase" |
| 认证器保障级别 |
| 使用的认证方法 |
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.jsonjson
{
"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.jsonjson
{
"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:
- Before starting any action → Log the action to
.sb-pentest-audit.log - After each discovery → Immediately update
.sb-pentest-context.json - 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.
不要批量在最后写入。而是:
- 开始任何操作前 → 将操作记录到
.sb-pentest-audit.log - 每次发现后 → 立即更新
.sb-pentest-context.json - 完成每个重要步骤后 → 将完成情况记录到
.sb-pentest-audit.log
这样可以确保如果技能被中断、崩溃或超时,所有截至该点的发现都已保存。
Required Actions (Progressive)
需执行的逐步操作
-
Updatewith extracted data:
.sb-pentest-context.jsonjson{ "jwts": { "found": 3, "api_keys": [ ... ], "user_tokens": [ ... ], "storage_patterns": [ ... ] } } -
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 -
If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
-
更新并写入提取的数据:
.sb-pentest-context.jsonjson{ "jwts": { "found": 3, "api_keys": [ ... ], "user_tokens": [ ... ], "storage_patterns": [ ... ] } } -
记录到:
.sb-pentest-audit.log[时间戳] [supabase-extract-jwt] [开始] 开始JWT提取 [时间戳] [supabase-extract-jwt] [成功] 找到3个JWT [时间戳] [supabase-extract-jwt] [上下文已更新] .sb-pentest-context.json已更新 -
如果文件不存在,在写入前创建。
不更新上下文文件是不被接受的。
MANDATORY: Evidence Collection
强制要求:证据收集
📁 Evidence Directory:
.sb-pentest-evidence/02-extraction/📁 证据目录:
.sb-pentest-evidence/02-extraction/Evidence Files to Create
需创建的证据文件
| File | Content |
|---|---|
| All JWTs found with analysis |
| 文件 | 内容 |
|---|---|
| 所有找到的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
相关技能
- — Specifically extracts the anon key
supabase-extract-anon-key - — Checks for service key (critical)
supabase-extract-service-key - — Analyzes auth configuration
supabase-audit-auth-config
- — 专门提取anon密钥
supabase-extract-anon-key - — 检查服务密钥(关键)
supabase-extract-service-key - — 分析认证配置
supabase-audit-auth-config