with one click
supabase-audit-tables-list
// List all tables exposed via the Supabase PostgREST API to identify the attack surface.
// List all tables exposed via the Supabase PostgREST API to identify the attack surface.
Orchestrate a complete Supabase security audit with guided step-by-step execution and ownership confirmation.
Test Row Level Security (RLS) policies for common bypass vulnerabilities and misconfigurations.
List and test exposed PostgreSQL RPC functions for security issues and potential RLS bypass.
Attempt to read data from exposed tables to verify actual data exposure and RLS effectiveness.
Analyze Supabase authentication configuration for security weaknesses and misconfigurations.
Test if user signup is open and identify potential abuse vectors in the registration process.
| name | supabase-audit-tables-list |
| description | List all tables exposed via the Supabase PostgREST API to identify the attack surface. |
š“ CRITICAL: PROGRESSIVE FILE UPDATES REQUIRED
You MUST write to context files AS YOU GO, not just at the end.
- Write to
.sb-pentest-context.jsonIMMEDIATELY after each discovery- Log to
.sb-pentest-audit.logBEFORE 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 discovers all database tables exposed through the Supabase PostgREST API.
Supabase exposes tables via PostgREST at:
https://[project-ref].supabase.co/rest/v1/
The skill uses the OpenAPI schema endpoint to enumerate tables:
https://[project-ref].supabase.co/rest/v1/?apikey=[anon-key]
By default, Supabase exposes tables in the public schema. Tables are exposed when:
public)REVOKE has been doneList tables exposed on my Supabase project
List all exposed tables with column details
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
EXPOSED TABLES
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Project: abc123def.supabase.co
Schema: public
Tables Found: 8
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Table Inventory
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
1. users
āāā Columns: id, email, name, avatar_url, created_at
āāā Primary Key: id (uuid)
āāā RLS Status: Unknown (test with supabase-audit-rls)
āāā Risk: ā ļø Contains user PII
2. profiles
āāā Columns: id, user_id, bio, website, social_links
āāā Primary Key: id (uuid)
āāā Foreign Key: user_id ā auth.users
āāā Risk: ā ļø Contains user PII
3. posts
āāā Columns: id, author_id, title, content, published, created_at
āāā Primary Key: id (uuid)
āāā Risk: ā¹ļø Content data
4. comments
āāā Columns: id, post_id, user_id, content, created_at
āāā Primary Key: id (uuid)
āāā Risk: ā¹ļø Content data
5. orders
āāā Columns: id, user_id, total, status, items, created_at
āāā Primary Key: id (uuid)
āāā Risk: š“ Contains financial/transaction data
6. products
āāā Columns: id, name, description, price, stock, image_url
āāā Primary Key: id (uuid)
āāā Risk: ā¹ļø Public catalog data
7. settings
āāā Columns: id, key, value, updated_at
āāā Primary Key: id (uuid)
āāā Risk: ā ļø May contain sensitive configuration
8. api_keys
āāā Columns: id, user_id, key_hash, name, last_used
āāā Primary Key: id (uuid)
āāā Risk: š“ Contains secrets
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Summary
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Total Tables: 8
High Risk: 2 (orders, api_keys)
Medium Risk: 3 (users, profiles, settings)
Low Risk: 3 (posts, comments, products)
Next Steps:
āāā Run supabase-audit-tables-read to test actual data access
āāā Run supabase-audit-rls to verify RLS policies
āāā Review high-risk tables first
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Tables are classified by likely content:
| Risk | Table Patterns | Examples |
|---|---|---|
| š“ High | Financial, secrets, auth | orders, payments, api_keys, secrets |
| ā ļø Medium | User PII, config | users, profiles, settings, preferences |
| ā¹ļø Low | Public content | posts, products, categories, tags |
{
"tables": {
"count": 8,
"list": [
{
"name": "users",
"schema": "public",
"columns": ["id", "email", "name", "avatar_url", "created_at"],
"primary_key": "id",
"risk_level": "medium",
"risk_reason": "Contains user PII"
},
{
"name": "orders",
"schema": "public",
"columns": ["id", "user_id", "total", "status", "items", "created_at"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Contains financial data"
}
],
"by_risk": {
"high": ["orders", "api_keys"],
"medium": ["users", "profiles", "settings"],
"low": ["posts", "comments", "products"]
}
}
}
Some tables may not appear in the OpenAPI schema:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ADDITIONAL DISCOVERY
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
Common Tables Not in Schema (testing existence):
āāā _prisma_migrations: ā Not found
āāā schema_migrations: ā Not found
āāā audit_log: ā
EXISTS but not in OpenAPI
āāā internal_config: ā Not found
Note: 'audit_log' exists but may have restricted access.
Test with supabase-audit-tables-read.
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
The skill also checks for non-public schemas:
Schema Exposure Check:
āāā public: ā
Exposed (8 tables)
āāā auth: ā Not directly exposed (expected)
āāā storage: ā Not directly exposed (expected)
āāā extensions: ā Not exposed (good)
āāā custom_schema: ā ļø Exposed (3 tables) - Review if intentional
ā Problem: No tables found ā Solution:
ā Problem: Too many tables listed ā Solution: This may indicate overly permissive schema exposure. Consider:
-- Restrict exposed schemas
ALTER ROLE anon SET search_path TO public;
ā Problem: Sensitive tables exposed ā Solution: Either remove from public schema or implement strict RLS.
-- Ensure RLS is enabled
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only see their own data
CREATE POLICY "Users see own data" ON users
FOR SELECT USING (auth.uid() = id);
-- Strict RLS for financial data
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users see own orders" ON orders
FOR SELECT USING (auth.uid() = user_id);
-- No public access even for admins via API
-- Use Edge Functions for admin operations
-- Consider not exposing at all
REVOKE ALL ON TABLE api_keys FROM anon, authenticated;
-- Or use views that hide sensitive columns
CREATE VIEW public.api_keys_safe AS
SELECT id, name, last_used FROM api_keys;
ā ļø This skill MUST update tracking files PROGRESSIVELY during execution, NOT just at the end.
DO NOT batch all writes at the end. Instead:
.sb-pentest-audit.log.sb-pentest-context.json.sb-pentest-audit.logThis ensures that if the skill is interrupted, crashes, or times out, all findings up to that point are preserved.
Update .sb-pentest-context.json with results:
{
"tables": {
"count": 8,
"list": [ ... ],
"by_risk": { "high": [], "medium": [], "low": [] }
}
}
Log to .sb-pentest-audit.log:
[TIMESTAMP] [supabase-audit-tables-list] [START] Listing exposed tables
[TIMESTAMP] [supabase-audit-tables-list] [SUCCESS] Found 8 tables
[TIMESTAMP] [supabase-audit-tables-list] [CONTEXT_UPDATED] .sb-pentest-context.json updated
If files don't exist, create them before writing.
FAILURE TO UPDATE CONTEXT FILES IS NOT ACCEPTABLE.
š Evidence Directory: .sb-pentest-evidence/03-api-audit/tables/
| File | Content |
|---|---|
tables-list.json | Complete list of exposed tables |
tables-metadata.json | Column details and types per table |
openapi-schema.json | Raw OpenAPI/PostgREST schema |
{
"evidence_id": "API-TBL-001",
"timestamp": "2025-01-31T10:15:00Z",
"category": "api-audit",
"type": "table_enumeration",
"request": {
"method": "GET",
"url": "https://abc123def.supabase.co/rest/v1/",
"headers": {
"apikey": "[REDACTED]"
},
"curl_command": "curl -s 'https://abc123def.supabase.co/rest/v1/' -H 'apikey: $ANON_KEY'"
},
"tables_found": [
{
"name": "users",
"schema": "public",
"columns": ["id", "email", "name", "created_at"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Contains PII"
},
{
"name": "orders",
"schema": "public",
"columns": ["id", "user_id", "total", "status"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Financial data"
}
],
"summary": {
"total_tables": 8,
"high_risk": 2,
"medium_risk": 3,
"low_risk": 3
}
}
# === TABLE ENUMERATION ===
# List all exposed tables via OpenAPI schema
curl -s "$SUPABASE_URL/rest/v1/" -H "apikey: $ANON_KEY"
supabase-audit-tables-read ā Test actual data accesssupabase-audit-rls ā Verify RLS policiessupabase-audit-rpc ā Check exposed functions