Loading...
Loading...
Discover and test Supabase Edge Functions for security vulnerabilities and misconfigurations.
npx skill4agent add yoanbernabeu/supabase-pentest-skills supabase-audit-functions🔴 CRITICAL: PROGRESSIVE FILE UPDATES REQUIREDYou MUST write to context files AS YOU GO, not just at the end.
- Write to
IMMEDIATELY after each function tested.sb-pentest-context.json- Log to
BEFORE and AFTER each function test.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.
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 |
| Test | Purpose |
|---|---|
| Function discovery | Find exposed functions |
| Auth requirements | Check if JWT required |
| Input validation | Test for injection |
| Error handling | Check for information disclosure |
Audit Edge Functions on my Supabase projectTest the process-payment Edge Function for security issues═══════════════════════════════════════════════════════════
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:
```json
{"message": "Hello, World!"}# 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!// 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 });
}// 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 });
}{
"error": "Invalid signature",
"expected": "sha256=abc123...",
"received": "sha256=xyz789..."
}// Generic error, log details server-side
if (!validSignature) {
console.error(`Invalid signature: expected ${expected}, got ${received}`);
return new Response('Unauthorized', { status: 401 });
}
## 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
```javascript
// Look for function invocations in client code
supabase.functions.invoke('function-name', {...})
fetch('/functions/v1/function-name', {...})404 Not Found → Function doesn't exist
401 Unauthorized → Function exists, needs auth
200 OK → Function exists, accessible{
"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"
}
]
}
}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
// ...
});// For user-specific resources
const requestedUserId = body.user_id;
const authenticatedUserId = user.id;
if (requestedUserId !== authenticatedUserId) {
return new Response('Forbidden', { status: 403 });
}// 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 });
}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 }
);
}.sb-pentest-audit.log.sb-pentest-context.json.sb-pentest-context.json{
"functions_audit": {
"timestamp": "...",
"functions_found": 5,
"findings": [ ... ]
}
}.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 updated.sb-pentest-evidence/07-functions-audit/| File | Content |
|---|---|
| List of discovered Edge Functions |
| Test results per function |
{
"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_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"
}
}supabase-audit-rpcsupabase-audit-auth-configsupabase-report