关于 supabase-extract-anon-key
用于从客户端代码中提取 Supabase anon 公共 API 密钥的安全审计技能。它搜索常见代码和环境变量写法,验证 JWT 内容,并将提取结果逐步记录。
主要功能
- 01搜索客户端代码中的 anon 密钥
- 02检查客户端初始化和环境变量写法
- 03验证 JWT 格式、角色和项目引用
- 04记录密钥来源并保存证据
- 05逐步更新上下文和审计日志
适用场景
- 01为 Supabase 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 匿名密钥提取
🔴 严重:必须逐步更新文件
你必须边执行边写入上下文文件,而不是等到最后才写入。
- 每发现一项内容后,立即写入
.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开头(base64 编码的{"alg":) - 负载中包含
"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— 检查是否泄露了关键服务密钥supabase-audit-rls— 测试 RLS 是否保护了你的数据supabase-audit-tables-read— 查看哪些数据可通过此密钥访问