
Supabase Extract Service Key
- 322 installs
- 60 repo stars
- Updated January 31, 2026
- yoanbernabeu/supabase-pentest-skills
supabase-extract-service-key is a Claude security skill that detects whether the Supabase service_role admin key has been accidentally exposed in client-side code for developers preventing P0 credential leaks before prod
About
supabase-extract-service-key is a Claude skill from yoanbernabeu/supabase-pentest-skills flagged as CRITICAL for detecting Supabase service_role key leaks in client-side code—a P0 severity issue. The skill scans JavaScript and TypeScript bundles for the admin credential that bypasses Row Level Security and must never ship in frontend assets. Findings write progressively to .sb-pentest-context.json and .sb-pentest-audit.log before and after each action so partial runs preserve evidence. Developers reach for supabase-extract-service-key during pre-deploy Supabase security reviews or CI secret-scanning gates. A positive detection should block release until the service_role key is rotated and removed from client code.
- Detects exposed Supabase service_role admin key in client code
- Critical pre-ship security check
- Distinguishes service key from anon key exposure
- Part of supabase-pentest-skills suite
Supabase Extract Service Key by the numbers
- 322 all-time installs (skills.sh)
- +13 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #612 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-extract-service-keyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 322 |
|---|---|
| repo stars | ★ 60 |
| Last updated | January 31, 2026 |
| Repository | yoanbernabeu/supabase-pentest-skills ↗ |
How do you detect Supabase service_role key leaks?
Detects whether the Supabase service_role key (an admin credential) has been accidentally exposed in client-side code, preventing a critical secret leak before shipping.
Who is it for?
Developers running pre-ship Supabase security audits who must confirm service_role keys never appear in client-side bundles.
Skip if: Backend-only services where service_role keys are correctly confined to server environment variables with no frontend exposure risk.
When should I use this skill?
A Supabase security review must confirm the service_role admin key is not exposed in client-side code before deploy.
What you get
P0 leak detection report, .sb-pentest-context.json entries, .sb-pentest-audit.log evidence trail, and remediation block recommendation.
- P0 leak detection report
- .sb-pentest-audit.log evidence trail
By the numbers
- Classified as P0 severity for service_role key exposure
- Writes progressively to .sb-pentest-context.json and .sb-pentest-audit.log
Files
Supabase Service Key Detection
🔴 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 detects if the service_role key (admin key) is accidentally exposed in client-side code.
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
Prerequisites
- Target application accessible
- Supabase detection completed (auto-invokes if needed)
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 Key vs Anon Key
| Aspect | Anon Key | Service Key |
|---|---|---|
| Role claim | "role": "anon" | "role": "service_role" |
| RLS | ✅ Respects RLS | ❌ Bypasses RLS |
| Client-side | ✅ Expected | ❌ NEVER |
| Server-side | ✅ Can use | ✅ Should use |
Detection Patterns
The skill searches for:
1. Key with service_role Claim
// Decoded JWT payload contains:
{
"role": "service_role", // ❌ CRITICAL if in client code
"iss": "supabase",
"ref": "abc123def"
}2. Variable Names
// Common naming patterns
SUPABASE_SERVICE_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_ADMIN_KEY
SUPABASE_SECRET_KEY
SERVICE_ROLE_KEY3. Accidental Exposure
// Sometimes exposed alongside anon key
const keys = {
anon: 'eyJ...',
service: 'eyJ...' // ❌ Should not be here
}Usage
Basic Check
Check for service key leak on https://myapp.example.comDeep Scan
Deep scan for service key exposure on https://myapp.example.comOutput 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 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
═══════════════════════════════════════════════════════════Context Output
Saved to .sb-pentest-context.json:
{
"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.mapCommon Causes
| Cause | Solution |
|---|---|
| Wrong env variable | Use NEXT_PUBLIC_ only for anon key |
| 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)
// ❌ 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
)After (Correct)
// ✅ 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' }
})Edge Function (Server-Side)
// 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
// ...
})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.
Required Actions (Progressive)
1. Update `.sb-pentest-context.json` with findings:
{
"supabase": {
"service_key_exposed": true/false,
"service_key_location": "path:line"
},
"findings": [
{
"id": "SERVICE_KEY_EXPOSED",
"severity": "P0",
"title": "Service Role Key Exposed",
...
}
]
}2. 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 updated3. If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
MANDATORY: Evidence Collection
📁 Evidence Directory: .sb-pentest-evidence/02-extraction/service-key-exposure/
Evidence Files to Create (if service key found)
| File | Content |
|---|---|
service-key-exposure/location.txt | File path and line number |
service-key-exposure/decoded-payload.json | Decoded JWT proving it's service_role |
service-key-exposure/code-snippet.txt | Code context (redacted) |
Evidence Format (P0 Finding)
{
"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)
## [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**Related Skills
supabase-extract-anon-key— Extract the (expected) anon keysupabase-audit-tables-read— Test what data is accessiblesupabase-report— Generate full report including this finding
Related skills
FAQ
Why is supabase-extract-service-key P0 severity?
supabase-extract-service-key flags P0 severity because a service_role key in client-side code grants admin access that bypasses Row Level Security. Exposed service_role credentials require immediate rotation and deploy blocking.
What happens when supabase-extract-service-key finds a leak?
supabase-extract-service-key logs the finding to .sb-pentest-context.json and .sb-pentest-audit.log progressively. Developers must rotate the service_role key, remove it from client bundles, and block release until remediation completes.