supabase-audit-tables-list
npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-audit-tables-list
Agent 安装分布
Skill 文档
List Exposed Tables
ð´ 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.
When to Use This Skill
- To understand the API attack surface
- Before testing RLS policies
- To inventory exposed data models
- As part of a comprehensive security audit
Prerequisites
- Supabase URL extracted (auto-invokes if needed)
- Anon key extracted (auto-invokes if needed)
How It Works
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]
What Gets Exposed
By default, Supabase exposes tables in the public schema. Tables are exposed when:
- They exist in an exposed schema (default:
public) - No explicit
REVOKEhas been done - PostgREST can see them
Usage
Basic Table List
List tables exposed on my Supabase project
With Schema Information
List all exposed tables with column details
Output Format
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
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
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Risk Classification
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 |
Context Output
{
"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"]
}
}
}
Hidden Tables
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.
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
Schema Analysis
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
Common Issues
â Problem: No tables found â Solution:
- Check if anon key is valid
- Verify project URL is correct
- The API may be disabled in project settings
â 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.
Recommendations by Table Type
User Tables
-- 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);
Order/Payment Tables
-- 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
Secret Tables
-- 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;
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:
- Before starting any action â Log the action to
.sb-pentest-audit.log - After each table discovered â Immediately update
.sb-pentest-context.json - 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)
-
Update
.sb-pentest-context.jsonwith 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.
MANDATORY: Evidence Collection
ð Evidence Directory: .sb-pentest-evidence/03-api-audit/tables/
Evidence Files to Create
| 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 Format
{
"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
}
}
Add to curl-commands.sh
# === TABLE ENUMERATION ===
# List all exposed tables via OpenAPI schema
curl -s "$SUPABASE_URL/rest/v1/" -H "apikey: $ANON_KEY"
Related Skills
supabase-audit-tables-readâ Test actual data accesssupabase-audit-rlsâ Verify RLS policiessupabase-audit-rpcâ Check exposed functions