supabase-extract-service-key
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSupabase Service Key Detection
Supabase服务密钥检测
🔴 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 detects if the service_role key (admin key) is accidentally exposed in client-side code.
🔴 严重警告:需要逐步更新文件你必须在操作过程中写入上下文文件,而不是只在最后写入。
- 每次发现问题后立即写入
.sb-pentest-context.json- 每次操作前后都要记录到
.sb-pentest-audit.log- 不要等到技能完成后才更新文件
- 如果技能崩溃或被中断,所有已发现的结果必须已保存
这不是可选要求。不逐步写入文件属于严重错误。
本技能用于检测service_role密钥(管理员密钥)是否意外暴露在客户端代码中。
When to Use This Skill
何时使用本技能
- As part of every security audit (this is critical)
- When reviewing code before production deployment
- After detecting Supabase usage to check for this common mistake
- 作为每次安全审计的一部分(这一点至关重要)
- 生产部署前的代码审查阶段
- 检测到使用Supabase后,检查这一常见错误
Prerequisites
前置条件
- Target application accessible
- Supabase detection completed (auto-invokes if needed)
- 可访问目标应用
- 已完成Supabase检测(如果需要会自动调用)
Why This Is Critical
为何这一点至关重要
The service_role key bypasses ALL Row Level Security (RLS) policies. If exposed:
| Impact | Description |
|---|---|
| 🔴 Full DB Access | Read/write/delete all data in all tables |
| 🔴 Auth Bypass | Access all user data without authentication |
| 🔴 Storage Access | Read/write all files in all buckets |
| 🔴 User Impersonation | Generate tokens for any user |
This is a P0 (Critical) finding that requires immediate action.
service_role密钥会绕过所有行级安全(RLS)策略。如果泄露:
| 影响 | 描述 |
|---|---|
| 🔴 完全数据库访问权限 | 可读写/删除所有表中的所有数据 |
| 🔴 身份验证绕过 | 无需身份验证即可访问所有用户数据 |
| 🔴 存储访问权限 | 可读写所有存储桶中的所有文件 |
| 🔴 用户模拟 | 可为任意用户生成令牌 |
这是需要立即处理的P0(严重)级别问题。
Service Key vs Anon Key
服务密钥与匿名密钥对比
| Aspect | Anon Key | Service Key |
|---|---|---|
| Role claim | | |
| RLS | ✅ Respects RLS | ❌ Bypasses RLS |
| Client-side | ✅ Expected | ❌ NEVER |
| Server-side | ✅ Can use | ✅ Should use |
| 方面 | 匿名密钥(Anon Key) | 服务密钥(Service Key) |
|---|---|---|
| 角色声明 | | |
| RLS | ✅ 遵循RLS策略 | ❌ 绕过RLS策略 |
| 客户端使用 | ✅ 允许 | ❌ 绝对禁止 |
| 服务端使用 | ✅ 允许 | ✅ 建议使用 |
Detection Patterns
检测模式
The skill searches for:
本技能会搜索以下内容:
1. Key with service_role Claim
1. 包含service_role声明的密钥
javascript
// Decoded JWT payload contains:
{
"role": "service_role", // ❌ CRITICAL if in client code
"iss": "supabase",
"ref": "abc123def"
}javascript
// 解码后的JWT负载包含:
{
"role": "service_role", // ❌ 如果在客户端代码中则为严重问题
"iss": "supabase",
"ref": "abc123def"
}2. Variable Names
2. 变量命名
javascript
// Common naming patterns
SUPABASE_SERVICE_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_ADMIN_KEY
SUPABASE_SECRET_KEY
SERVICE_ROLE_KEYjavascript
// 常见命名模式
SUPABASE_SERVICE_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_ADMIN_KEY
SUPABASE_SECRET_KEY
SERVICE_ROLE_KEY3. Accidental Exposure
3. 意外暴露
javascript
// Sometimes exposed alongside anon key
const keys = {
anon: 'eyJ...',
service: 'eyJ...' // ❌ Should not be here
}javascript
// 有时会和匿名密钥一起暴露
const keys = {
anon: 'eyJ...',
service: 'eyJ...' // ❌ 不应该出现在这里
}Usage
使用方法
Basic Check
基础检查
Check for service key leak on https://myapp.example.com检查https://myapp.example.com上的服务密钥泄露情况Deep Scan
深度扫描
Deep scan for service key exposure on https://myapp.example.com深度扫描https://myapp.example.com上的服务密钥暴露情况Output Format
输出格式
No Service Key Found (Good)
未发现服务密钥(正常情况)
═══════════════════════════════════════════════════════════
SERVICE KEY CHECK
═══════════════════════════════════════════════════════════
Status: ✅ No service_role key detected in client code
Scanned:
├── HTML source: Clean
├── JavaScript bundles: 5 files, 2.3MB analyzed
├── Inline scripts: 12 blocks checked
└── Source maps: Not exposed (good)
JWT Analysis:
└── 1 key found, confirmed role=anon (safe)
Result: PASS - No critical key exposure
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
服务密钥检查
═══════════════════════════════════════════════════════════
状态: ✅ 客户端代码中未检测到service_role密钥
已扫描内容:
├── HTML源码: 无问题
├── JavaScript包: 5个文件,已分析2.3MB
├── 内联脚本: 检查了12个代码块
└── 源映射: 未暴露(正常)
JWT分析:
└── 找到1个密钥,确认角色为anon(安全)
结果: 通过 - 无严重密钥暴露问题
═══════════════════════════════════════════════════════════Service Key FOUND (Critical)
发现服务密钥(严重情况)
═══════════════════════════════════════════════════════════
🔴 CRITICAL: SERVICE KEY EXPOSED
═══════════════════════════════════════════════════════════
Severity: P0 - CRITICAL
Status: ❌ service_role key found in client-side code!
⚠️ IMMEDIATE ACTION REQUIRED ⚠️
Exposed Key:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBh
YmFzZSIsInJlZiI6ImFiYzEyM2RlZiIsInJvbGUiOiJzZXJ2aWNlX3
JvbGUiLCJpYXQiOjE2NDAwMDAwMDAsImV4cCI6MTk1NTM2MDAwMH0
.xxxxxxxxxxxxx
Location:
└── /static/js/admin.chunk.js (line 89)
const SUPABASE_KEY = 'eyJhbG...' // Used in createClient()
Decoded Payload:
├── role: service_role ← CRITICAL
├── ref: abc123def
└── exp: 2031-12-20
Impact Assessment:
├── 🔴 Full database access possible
├── 🔴 All RLS policies bypassed
├── 🔴 All user data exposed
└── 🔴 All storage buckets accessible
═══════════════════════════════════════════════════════════
IMMEDIATE REMEDIATION STEPS
═══════════════════════════════════════════════════════════
1. ROTATE THE KEY NOW
→ Supabase Dashboard > Settings > API > Regenerate service_role key
2. REMOVE FROM CLIENT CODE
→ Delete the key from your source code
→ Redeploy your application
3. AUDIT FOR ABUSE
→ Check Supabase logs for unauthorized access
→ Review database for unexpected changes
4. USE EDGE FUNCTIONS
→ Move privileged operations to Edge Functions
→ Client calls Edge Function, which uses service key server-side
Documentation:
→ https://supabase.com/docs/guides/api/api-keys
→ https://supabase.com/docs/guides/functions
══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
🔴 严重警告:服务密钥已暴露
═══════════════════════════════════════════════════════════
严重级别: P0 - 严重
状态: ❌ 客户端代码中发现service_role密钥!
⚠️ 需要立即采取行动 ⚠️
暴露的密钥:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBh
YmFzZSIsInJlZiI6ImFiYzEyM2RlZiIsInJvbGUiOiJzZXJ2aWNlX3
JvbGUiLCJpYXQiOjE2NDAwMDAwMDAsImV4cCI6MTk1NTM2MDAwMH0
.xxxxxxxxxxxxx
位置:
└── /static/js/admin.chunk.js(第89行)
const SUPABASE_KEY = 'eyJhbG...' // 用于createClient()
解码后的负载:
├── role: service_role ← 严重问题
├── ref: abc123def
└── exp: 2031-12-20
影响评估:
├── 🔴 可获取完整数据库访问权限
├── 🔴 所有RLS策略被绕过
├── 🔴 所有用户数据暴露
└── 🔴 所有存储桶可访问
═══════════════════════════════════════════════════════════
立即修复步骤
═══════════════════════════════════════════════════════════
1. 立即轮换密钥
→ Supabase控制台 > 设置 > API > 重新生成service_role密钥
2. 从客户端代码中移除
→ 从源码中删除该密钥
→ 重新部署应用
3. 审计是否存在滥用情况
→ 检查Supabase日志中的未授权访问记录
→ 检查数据库是否有异常变更
4. 使用Edge Functions
→ 将特权操作迁移到Edge Functions
→ 客户端调用Edge Function,由其在服务端使用服务密钥
相关文档:
→ https://supabase.com/docs/guides/api/api-keys
→ https://supabase.com/docs/guides/functions
═══════════════════════════════════════════════════════════Context Output
上下文输出
Saved to :
.sb-pentest-context.jsonjson
{
"findings": [
{
"id": "SERVICE_KEY_EXPOSED",
"severity": "P0",
"title": "Service Role Key Exposed in Client Code",
"description": "The service_role key was found in client-side JavaScript",
"location": {
"file": "/static/js/admin.chunk.js",
"line": 89
},
"evidence": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"role": "service_role",
"project_ref": "abc123def"
},
"remediation": {
"immediate": "Rotate key in Supabase Dashboard",
"long_term": "Move to Edge Functions",
"docs": "https://supabase.com/docs/guides/api/api-keys"
}
}
],
"supabase": {
"service_key_exposed": true,
"service_key_location": "/static/js/admin.chunk.js:89"
}
}保存到:
.sb-pentest-context.jsonjson
{
"findings": [
{
"id": "SERVICE_KEY_EXPOSED",
"severity": "P0",
"title": "Service Role Key Exposed in Client Code",
"description": "The service_role key was found in client-side JavaScript",
"location": {
"file": "/static/js/admin.chunk.js",
"line": 89
},
"evidence": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"role": "service_role",
"project_ref": "abc123def"
},
"remediation": {
"immediate": "Rotate key in Supabase Dashboard",
"long_term": "Move to Edge Functions",
"docs": "https://supabase.com/docs/guides/api/api-keys"
}
}
],
"supabase": {
"service_key_exposed": true,
"service_key_location": "/static/js/admin.chunk.js:89"
}
}Source Maps Check
源映射检查
The skill also checks for exposed source maps that might reveal keys:
Source Maps Analysis:
├── main.js.map: ❌ Exposed (may contain secrets)
├── vendor.js.map: ❌ Exposed
└── Recommendation: Disable source maps in production
To check source maps content:
→ Add .map to JS URLs: /static/js/main.js.map本技能还会检查是否存在可能泄露密钥的暴露源映射:
源映射分析:
├── main.js.map: ❌ 已暴露(可能包含敏感信息)
├── vendor.js.map: ❌ 已暴露
└── 建议: 生产环境中禁用源映射
检查源映射内容的方法:
→ 在JS URL后添加.map: /static/js/main.js.mapCommon Causes
常见原因
| Cause | Solution |
|---|---|
| Wrong env variable | Use |
| Copy-paste error | Double-check which key you're using |
| Debug code left in | Remove before production build |
| Misconfigured bundler | Ensure service key env vars are not included |
| 原因 | 解决方案 |
|---|---|
| 环境变量使用错误 | 仅对匿名密钥使用 |
| 复制粘贴错误 | 仔细检查所使用的密钥 |
| 遗留调试代码 | 生产构建前移除调试代码 |
| 打包工具配置错误 | 确保服务密钥的环境变量未被包含在打包内容中 |
Remediation Code Examples
修复代码示例
Before (Wrong)
修复前(错误写法)
javascript
// ❌ WRONG - Service key in client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_SERVICE_KEY // ❌ NEVER DO THIS
)javascript
// ❌ 错误 - 客户端使用服务密钥
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_SERVICE_KEY // ❌ 绝对不要这样做
)After (Correct)
修复后(正确写法)
javascript
// ✅ CORRECT - Only anon key in client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY // ✅ Safe for client
)
// For privileged operations, call an Edge Function:
const { data } = await supabase.functions.invoke('admin-action', {
body: { action: 'delete-user', userId: '123' }
})javascript
// ✅ 正确 - 客户端仅使用匿名密钥
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY // ✅ 客户端使用安全
)
// 对于特权操作,调用Edge Functions:
const { data } = await supabase.functions.invoke('admin-action', {
body: { action: 'delete-user', userId: '123' }
})Edge Function (Server-Side)
Edge Function(服务端)
typescript
// supabase/functions/admin-action/index.ts
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// ✅ Service key only on server
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') // ✅ Safe on server
)
// Perform privileged operation
// ...
})typescript
// supabase/functions/admin-action/index.ts
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// ✅ 仅在服务端使用服务密钥
const supabase = createClient(
Deno.env.get('SUPABASE_URL'),
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') // ✅ 服务端使用安全
)
// 执行特权操作
// ...
})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 findings:
.sb-pentest-context.jsonjson{ "supabase": { "service_key_exposed": true/false, "service_key_location": "path:line" }, "findings": [ { "id": "SERVICE_KEY_EXPOSED", "severity": "P0", "title": "Service Role Key Exposed", ... } ] } -
Log to:
.sb-pentest-audit.log[TIMESTAMP] [supabase-extract-service-key] [START] Checking for service key exposure [TIMESTAMP] [supabase-extract-service-key] [CRITICAL] Service key EXPOSED at path:line [TIMESTAMP] [supabase-extract-service-key] [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{ "supabase": { "service_key_exposed": true/false, "service_key_location": "path:line" }, "findings": [ { "id": "SERVICE_KEY_EXPOSED", "severity": "P0", "title": "Service Role Key Exposed", ... } ] } -
记录到:
.sb-pentest-audit.log[TIMESTAMP] [supabase-extract-service-key] [START] Checking for service key exposure [TIMESTAMP] [supabase-extract-service-key] [CRITICAL] Service key EXPOSED at path:line [TIMESTAMP] [supabase-extract-service-key] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,在写入前创建文件。
不更新上下文文件是不被允许的。
MANDATORY: Evidence Collection
强制要求:证据收集
📁 Evidence Directory:
.sb-pentest-evidence/02-extraction/service-key-exposure/📁 证据目录:
.sb-pentest-evidence/02-extraction/service-key-exposure/Evidence Files to Create (if service key found)
需创建的证据文件(如果发现服务密钥)
| File | Content |
|---|---|
| File path and line number |
| Decoded JWT proving it's service_role |
| Code context (redacted) |
| 文件 | 内容 |
|---|---|
| 文件路径和行号 |
| 解码后的JWT,证明其为service_role密钥 |
| 代码上下文(已脱敏) |
Evidence Format (P0 Finding)
P0级问题的证据格式
json
{
"evidence_id": "EXT-SVC-001",
"timestamp": "2025-01-31T10:10:00Z",
"category": "extraction",
"type": "service_key_exposure",
"severity": "P0",
"finding_id": "P0-001",
"key_data": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"key_suffix": "...xxxx",
"role": "service_role"
},
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "service_role",
"iat": "2021-12-20T00:00:00Z",
"exp": "2031-12-20T00:00:00Z"
},
"location": {
"file": "/static/js/admin.chunk.js",
"line": 89,
"context": "const SUPABASE_KEY = 'eyJhbG...' // [REDACTED]"
},
"impact": {
"rls_bypass": true,
"full_db_access": true,
"auth_users_access": true,
"storage_access": true
},
"curl_command": "curl -X GET 'https://abc123def.supabase.co/rest/v1/users' -H 'apikey: [SERVICE_KEY]' -H 'Authorization: Bearer [SERVICE_KEY]'"
}json
{
"evidence_id": "EXT-SVC-001",
"timestamp": "2025-01-31T10:10:00Z",
"category": "extraction",
"type": "service_key_exposure",
"severity": "P0",
"finding_id": "P0-001",
"key_data": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"key_suffix": "...xxxx",
"role": "service_role"
},
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "service_role",
"iat": "2021-12-20T00:00:00Z",
"exp": "2031-12-20T00:00:00Z"
},
"location": {
"file": "/static/js/admin.chunk.js",
"line": 89,
"context": "const SUPABASE_KEY = 'eyJhbG...' // [REDACTED]"
},
"impact": {
"rls_bypass": true,
"full_db_access": true,
"auth_users_access": true,
"storage_access": true
},
"curl_command": "curl -X GET 'https://abc123def.supabase.co/rest/v1/users' -H 'apikey: [SERVICE_KEY]' -H 'Authorization: Bearer [SERVICE_KEY]'"
}Add to timeline.md (P0)
添加到timeline.md(P0级问题)
markdown
undefinedmarkdown
undefined[TIMESTAMP] - 🔴 P0 CRITICAL: Service Role Key Exposed
[TIMESTAMP] - 🔴 P0 CRITICAL: Service Role Key Exposed
- Service role key found in client-side code
- Location: [file]:[line]
- Impact: Full database access, RLS bypass
- Evidence:
02-extraction/service-key-exposure/ - IMMEDIATE ACTION REQUIRED
undefined- Service role key found in client-side code
- Location: [file]:[line]
- Impact: Full database access, RLS bypass
- Evidence:
02-extraction/service-key-exposure/ - IMMEDIATE ACTION REQUIRED
undefinedRelated Skills
相关技能
- — Extract the (expected) anon key
supabase-extract-anon-key - — Test what data is accessible
supabase-audit-tables-read - — Generate full report including this finding
supabase-report
- — 提取(预期的)匿名密钥
supabase-extract-anon-key - — 测试可访问的数据内容
supabase-audit-tables-read - — 生成包含该问题的完整报告
supabase-report