MCPInstall

supabase-extract-service-key

CRITICAL - Detect if the Supabase servicerole key is leaked in client-side code. This is a P0 severity issue.

Installs
481
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-extract-service-key
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads supabase-extract-service-key automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

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:

ImpactDescription
🔴 Full DB AccessRead/write/delete all data in all tables
🔴 Auth BypassAccess all user data without authentication
🔴 Storage AccessRead/write all files in all buckets
🔴 User ImpersonationGenerate tokens for any user

This is a P0 (Critical) finding that requires immediate action.

Service Key vs Anon Key

AspectAnon KeyService 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_KEY

3. 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.com

Deep Scan

Deep scan for service key exposure on 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 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.map

Common Causes

CauseSolution
Wrong env variableUse NEXT_PUBLIC_ only for anon key
Copy-paste errorDouble-check which key you're using
Debug code left inRemove before production build
Misconfigured bundlerEnsure 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 updated
    
  3. 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)

FileContent
service-key-exposure/location.txtFile path and line number
service-key-exposure/decoded-payload.jsonDecoded JWT proving it's service_role
service-key-exposure/code-snippet.txtCode 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 key
  • supabase-audit-tables-read — Test what data is accessible
  • supabase-report — Generate full report including this finding

FAQ

What does the supabase-extract-service-key skill do?

CRITICAL - Detect if the Supabase servicerole key is leaked in client-side code. This is a P0 severity issue.

How do I install supabase-extract-service-key?

Run npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-extract-service-key in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/supabase-extract-service-key/ (personal) or .claude/skills/supabase-extract-service-key/ (project).

Which AI agents can use supabase-extract-service-key?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is supabase-extract-service-key safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains supabase-extract-service-key?

It is published by yoanbernabeu in yoanbernabeu/supabase-pentest-skills. It has 481 recorded installs.

More from yoanbernabeu/supabase-pentest-skills

View all →

supabase-audit-rls

yoanbernabeu/supabase-pentest-skills

Test Row Level Security (RLS) policies for common bypass vulnerabilities and misconfigurations.

Security1.1K installs

supabase-audit-functions

yoanbernabeu/supabase-pentest-skills

Discover and test Supabase Edge Functions for security vulnerabilities and misconfigurations.

Security934 installs

supabase-pentest

yoanbernabeu/supabase-pentest-skills

Orchestrate a complete Supabase security audit with guided step-by-step execution and ownership confirmation.

Security701 installs

supabase-audit-auth-config

yoanbernabeu/supabase-pentest-skills

Analyze Supabase authentication configuration for security weaknesses and misconfigurations.

Data & Databases552 installs

supabase-audit-rpc

yoanbernabeu/supabase-pentest-skills

List and test exposed PostgreSQL RPC functions for security issues and potential RLS bypass.

Data & Databases527 installs

supabase-audit-realtime

yoanbernabeu/supabase-pentest-skills

Test Supabase Realtime WebSocket channels for unauthorized subscriptions and data exposure.

Data & Databases523 installs

Popular data & databases skills

View category →

Postgres best practices maintained by Supabase, for Postgres running anywhere. Load this skill BEFORE writing or changing anything that lives in a Postgres database: creating or altering tables and columns (including choosing column types), schema design, migrations and declarative schema files, RLS policies and the tests that verify them, indexes, triggers, database functions, queues and scheduled jobs (pgcron, pgmq), vector/semantic search (pgvector), and restoring dumps (pgrestore) or importing data. Also load it when diagnosing slow queries, high CPU, timeouts, EXPLAIN plans, connection exhaustion, locking, bloat, or rows visible to the wrong user or tenant. This is not just a performance guide — schema, migration, security, and SQL authoring tasks need these rules too, even for a one-column change or a single query.

OfficialData & Databases462.2K installs

prisma-client-api

prisma/skills

Prisma Client API reference covering model queries, filters, operators, and client methods. Use when writing database queries, using CRUD operations, filtering data, or configuring Prisma Client. Triggers on "prisma query", "findMany", "create", "update", "delete", "$transaction".

OfficialData & Databases393.5K installs

Deprecated compatibility name for prisma-orm-setup. Use only when a user or existing integration explicitly invokes prisma-database-setup; otherwise select prisma-orm-setup.

OfficialData & Databases392.3K installs

prisma-cli

prisma/skills

Prisma ORM 7 CLI reference for existing Prisma 7 applications or explicitly selected Prisma 7 workflows. Covers prisma init, generate, migrate, db, dev, studio, and mcp. For setup, connection repair, or Prisma 8, use prisma-orm-setup; not the Prisma Platform CLI.

OfficialData & Databases390.8K installs

prisma-postgres

prisma/skills

Deprecated compatibility name for prisma-postgres-setup. Use only when a user or existing integration explicitly invokes prisma-postgres; otherwise select prisma-postgres-setup.

OfficialData & Databases384.4K installs

Required reference for Prisma ORM 7 SQL driver adapter work. Use when implementing or modifying adapters, adding database drivers, or touching SqlDriverAdapter, Transaction, savepoint, result mapping, or DriverAdapterError behavior. Covers current transaction lifecycle, optional savepoint hooks, original database-error preservation, and verification.

OfficialData & Databases378.9K installs