
Supabase Audit Functions
- 354 installs
- 60 repo stars
- Updated January 31, 2026
- yoanbernabeu/supabase-pentest-skills
supabase-audit-functions is a Supabase security skill that discovers and tests Edge Functions for vulnerabilities, writing progressive findings to JSON and log files for developers hardening serverless backends.
About
supabase-audit-functions is a Supabase pentest skill from yoanbernabeu/supabase-pentest-skills for developers security-testing Edge Functions before production launch. The skill discovers all exposed Supabase Edge Functions in a project, tests each for security vulnerabilities and misconfigurations, and mandates progressive writes to `.sb-pentest-context.json` and `.sb-pentest-audit.log` after every function tested so interrupted runs retain findings. Developers reach for supabase-audit-functions during pre-release hardening or authorized penetration tests of Supabase backends. The workflow emphasizes immediate persistence rather than end-of-run dumps, preventing data loss if the agent crashes mid-audit. Use it when Edge Function attack surface must be enumerated and validated with structured evidence. Skip it for non-Supabase stacks, unauthorized targets, or teams needing only RLS policy review without function testing.
- Automated discovery of all Supabase Edge Functions
- Security vulnerability testing across each discovered function
- Real-time findings logged to .sb-pentest-context.json and .sb-pentest-audit.log
- Part of a 24-skill Supabase penetration testing suite
- For authorized internal security assessments only
Supabase Audit Functions by the numbers
- 354 all-time installs (skills.sh)
- +14 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #576 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-audit-functionsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 354 |
|---|---|
| repo stars | ★ 60 |
| Last updated | January 31, 2026 |
| Repository | yoanbernabeu/supabase-pentest-skills ↗ |
How do you security-test Supabase Edge Functions?
Discover and security-test all exposed Supabase Edge Functions in a project, logging vulnerabilities and findings to structured JSON and log files for review.
Who is it for?
Developers or security engineers conducting authorized Supabase Edge Function audits who need progressive, crash-safe finding logs.
Skip if: Unauthorized penetration tests, non-Supabase backends, or teams needing only database RLS review without Edge Function testing.
When should I use this skill?
A developer asks to audit, discover, or security-test Supabase Edge Functions and log vulnerabilities to structured files.
What you get
Structured JSON context file, audit log entries, and per-function vulnerability findings for Supabase Edge Functions.
- .sb-pentest-context.json
- .sb-pentest-audit.log
By the numbers
- Writes to `.sb-pentest-context.json` after each function tested
- Logs to `.sb-pentest-audit.log` before and after each function test
Files
Edge Functions Audit
🔴 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 function tested- Log to .sb-pentest-audit.log BEFORE and AFTER each function test- 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 discovers and tests Supabase Edge Functions for security issues.
When to Use This Skill
- To discover exposed Edge Functions
- To test function authentication requirements
- To check for input validation issues
- As part of comprehensive security audit
Prerequisites
- Supabase URL available
- Detection completed
Understanding Edge Functions
Supabase Edge Functions are Deno-based serverless functions:
https://[project].supabase.co/functions/v1/[function-name]| Security Aspect | Consideration |
|---|---|
| Authentication | Functions can require JWT or be public |
| CORS | Cross-origin access control |
| Input Validation | User input handling |
| Secrets | Environment variable exposure |
Tests Performed
| Test | Purpose |
|---|---|
| Function discovery | Find exposed functions |
| Auth requirements | Check if JWT required |
| Input validation | Test for injection |
| Error handling | Check for information disclosure |
Usage
Basic Function Audit
Audit Edge Functions on my Supabase projectTest Specific Function
Test the process-payment Edge Function for security issuesOutput Format
═══════════════════════════════════════════════════════════
EDGE FUNCTIONS AUDIT
═══════════════════════════════════════════════════════════
Project: abc123def.supabase.co
Endpoint: https://abc123def.supabase.co/functions/v1/
─────────────────────────────────────────────────────────
Function Discovery
─────────────────────────────────────────────────────────
Discovery Method: Common name enumeration + client code analysis
Functions Found: 5
─────────────────────────────────────────────────────────
1. hello-world
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/hello-world
Method: GET, POST
Authentication Test:
├── Without JWT: ✅ 200 OK
└── Status: ℹ️ Public function (no auth required)
Response:{"message": "Hello, World!"}
Assessment: ✅ APPROPRIATE
Simple public endpoint, no sensitive operations.
─────────────────────────────────────────────────────────
2. process-payment
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/process-payment
Method: POST
Authentication Test:
├── Without JWT: ❌ 401 Unauthorized
├── With valid JWT: ✅ 200 OK
└── Status: ✅ Authentication required
Input Validation Test:
├── Missing amount: ❌ 400 Bad Request (good)
├── Negative amount: ❌ 400 Bad Request (good)
├── String amount: ❌ 400 Bad Request (good)
└── Valid input: ✅ 200 OK
Error Response Test:
├── Error format: Generic message (good)
└── Stack trace: ❌ Not exposed (good)
Assessment: ✅ PROPERLY SECURED
Requires auth, validates input, safe error handling.
─────────────────────────────────────────────────────────
3. get-user-data
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/get-user-data
Method: GET
Authentication Test:
├── Without JWT: ❌ 401 Unauthorized
└── Status: ✅ Authentication required
Authorization Test:
├── Request own data: ✅ 200 OK
├── Request other user's data: ✅ 200 OK ← 🔴 P0!
└── Status: 🔴 BROKEN ACCESS CONTROL
Test:As user A, request user B's data
curl https://abc123def.supabase.co/functions/v1/get-user-data?user_id=user-b-id \ -H "Authorization: Bearer [user-a-token]"
Returns user B's data!
Finding: 🔴 P0 - IDOR VULNERABILITY
Function accepts user_id parameter without verifying
that the authenticated user is requesting their own data.
Fix:// In Edge Function const { user_id } = await req.json(); const jwt_user = getUser(req); // From JWT
// Verify ownership if (user_id !== jwt_user.id) { return new Response('Forbidden', { status: 403 }); }
─────────────────────────────────────────────────────────
4. admin-panel
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/admin-panel
Method: GET, POST
Authentication Test:
├── Without JWT: ❌ 401 Unauthorized
├── With regular user JWT: ✅ 200 OK ← 🔴 P0!
└── Status: 🔴 MISSING ROLE CHECK
Finding: 🔴 P0 - PRIVILEGE ESCALATION
Admin function accessible to any authenticated user.
No role verification in function code.
Fix:// Verify admin role const user = getUser(req); const { data: profile } = await supabase .from('profiles') .select('is_admin') .eq('id', user.id) .single();
if (!profile?.is_admin) { return new Response('Forbidden', { status: 403 }); }
─────────────────────────────────────────────────────────
5. webhook-handler
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/webhook-handler
Method: POST
Authentication Test:
├── Without JWT: ✅ 200 OK (expected for webhooks)
└── Status: ℹ️ Public (webhook endpoints are typically public)
Webhook Security Test:
├── Signature validation: ⚠️ Unable to test (need valid signature)
└── Rate limiting: Unknown
Error Response Test:{ "error": "Invalid signature", "expected": "sha256=abc123...", "received": "sha256=xyz789..." }
Finding: 🟠 P1 - INFORMATION DISCLOSURE
Error response reveals expected signature format.
Could help attacker understand validation mechanism.
Fix:// Generic error, log details server-side if (!validSignature) { console.error(Invalid signature: expected ${expected}, got ${received}); return new Response('Unauthorized', { status: 401 }); }
─────────────────────────────────────────────────────────
Summary
─────────────────────────────────────────────────────────
Functions Found: 5
Security Assessment:
├── ✅ Secure: 2 (hello-world, process-payment)
├── 🔴 P0: 2 (get-user-data IDOR, admin-panel privilege escalation)
└── 🟠 P1: 1 (webhook-handler info disclosure)
Critical Findings:
1. IDOR in get-user-data - any user can access any user's data
2. Missing role check in admin-panel - any user is admin
Priority Actions:
1. Fix get-user-data to verify user owns requested data
2. Add admin role verification to admin-panel
3. Fix webhook-handler error messages
═══════════════════════════════════════════════════════════Common Function Vulnerabilities
| Vulnerability | Description | Severity |
|---|---|---|
| No auth | Function accessible without JWT | P0-P2 |
| IDOR | User can access other users' data | P0 |
| Missing role check | Regular user accesses admin functions | P0 |
| Input injection | User input not validated | P0-P1 |
| Info disclosure | Errors reveal internal details | P1-P2 |
| CORS misconfigured | Accessible from unintended origins | P1-P2 |
Function Discovery Methods
1. Client Code Analysis
// Look for function invocations in client code
supabase.functions.invoke('function-name', {...})
fetch('/functions/v1/function-name', {...})2. Common Name Enumeration
Tested function names:
- hello-world, hello, test
- process-payment, payment, checkout
- get-user-data, user, profile
- admin, admin-panel, dashboard
- webhook, webhook-handler, stripe-webhook
- send-email, notify, notification
3. Error Response Analysis
404 Not Found → Function doesn't exist
401 Unauthorized → Function exists, needs auth
200 OK → Function exists, accessibleContext Output
{
"functions_audit": {
"timestamp": "2025-01-31T14:30:00Z",
"functions_found": 5,
"findings": [
{
"function": "get-user-data",
"severity": "P0",
"vulnerability": "IDOR",
"description": "Any authenticated user can access any user's data",
"remediation": "Verify user owns requested resource"
},
{
"function": "admin-panel",
"severity": "P0",
"vulnerability": "Privilege Escalation",
"description": "No role check, any authenticated user is admin",
"remediation": "Add admin role verification"
}
]
}
}Secure Function Patterns
Authentication Check
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// Get JWT from header
const authHeader = req.headers.get('Authorization');
if (!authHeader) {
return new Response('Unauthorized', { status: 401 });
}
// Verify JWT with Supabase
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!,
{ global: { headers: { Authorization: authHeader } } }
);
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) {
return new Response('Unauthorized', { status: 401 });
}
// User is authenticated
// ...
});Authorization Check (IDOR Prevention)
// For user-specific resources
const requestedUserId = body.user_id;
const authenticatedUserId = user.id;
if (requestedUserId !== authenticatedUserId) {
return new Response('Forbidden', { status: 403 });
}Role Check (Admin)
// Check admin role
const { data: profile } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single();
if (profile?.role !== 'admin') {
return new Response('Forbidden', { status: 403 });
}Input Validation
import { z } from 'zod';
const PaymentSchema = z.object({
amount: z.number().positive().max(10000),
currency: z.enum(['usd', 'eur', 'gbp']),
description: z.string().max(200).optional()
});
// Validate input
const result = PaymentSchema.safeParse(body);
if (!result.success) {
return new Response(
JSON.stringify({ error: 'Invalid input' }),
{ status: 400 }
);
}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 testing each function → Log the action to .sb-pentest-audit.log 2. After each vulnerability found → Immediately update .sb-pentest-context.json 3. After each function test completes → Log the result immediately
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 results:
{
"functions_audit": {
"timestamp": "...",
"functions_found": 5,
"findings": [ ... ]
}
}2. Log to `.sb-pentest-audit.log`:
[TIMESTAMP] [supabase-audit-functions] [START] Auditing Edge Functions
[TIMESTAMP] [supabase-audit-functions] [FINDING] P0: IDOR in get-user-data
[TIMESTAMP] [supabase-audit-functions] [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/07-functions-audit/
Evidence Files to Create
| File | Content |
|---|---|
discovered-functions.json | List of discovered Edge Functions |
function-tests/[name].json | Test results per function |
Evidence Format (IDOR Vulnerability)
{
"evidence_id": "FN-001",
"timestamp": "2025-01-31T11:10:00Z",
"category": "functions-audit",
"type": "idor_vulnerability",
"severity": "P0",
"function": "get-user-data",
"endpoint": "https://abc123def.supabase.co/functions/v1/get-user-data",
"tests": [
{
"test_name": "auth_required",
"request": {
"method": "GET",
"headers": {},
"curl_command": "curl '$URL/functions/v1/get-user-data'"
},
"response": {"status": 401},
"result": "PASS"
},
{
"test_name": "idor_test",
"description": "As user A, request user B's data",
"request": {
"method": "GET",
"url": "$URL/functions/v1/get-user-data?user_id=user-b-id",
"headers": {"Authorization": "Bearer [USER_A_TOKEN]"},
"curl_command": "curl '$URL/functions/v1/get-user-data?user_id=user-b-id' -H 'Authorization: Bearer [USER_A_TOKEN]'"
},
"response": {
"status": 200,
"body": {"id": "user-b-id", "email": "[REDACTED]", "data": "[REDACTED]"}
},
"result": "VULNERABLE",
"impact": "Any authenticated user can access any other user's data"
}
],
"remediation": "Add ownership check: if (user_id !== jwt_user.id) return 403"
}Evidence Format (Privilege Escalation)
{
"evidence_id": "FN-002",
"timestamp": "2025-01-31T11:15:00Z",
"category": "functions-audit",
"type": "privilege_escalation",
"severity": "P0",
"function": "admin-panel",
"test": {
"description": "Regular user accessing admin function",
"request": {
"method": "GET",
"headers": {"Authorization": "Bearer [REGULAR_USER_TOKEN]"},
"curl_command": "curl '$URL/functions/v1/admin-panel' -H 'Authorization: Bearer [REGULAR_USER_TOKEN]'"
},
"response": {
"status": 200,
"body": {"admin_data": "[REDACTED]"}
},
"result": "VULNERABLE",
"impact": "Any authenticated user has admin access"
}
}Related Skills
supabase-audit-rpc— Database functions (different from Edge Functions)supabase-audit-auth-config— Auth configurationsupabase-report— Include in final report
Related skills
How it compares
Pick supabase-audit-functions over generic API scanners when you need Supabase Edge Function discovery plus crash-safe structured pentest logs.
FAQ
What files does supabase-audit-functions write?
supabase-audit-functions writes progressively to `.sb-pentest-context.json` after each function tested and logs to `.sb-pentest-audit.log` before and after every function security test.
Why is progressive file writing required?
supabase-audit-functions requires progressive writes so findings survive agent crashes or interruptions; waiting until the skill completes is treated as a critical error.