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.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 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 REVOKE has 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 βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-
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
-
profiles βββ Columns: id, user_id, bio, website, social_links βββ Primary Key: id (uuid) βββ Foreign Key: user_id β auth.users βββ Risk: β οΈ Contains user PII
-
posts βββ Columns: id, author_id, title, content, published, created_at βββ Primary Key: id (uuid) βββ Risk: βΉοΈ Content data
-
comments βββ Columns: id, post_id, user_id, content, created_at βββ Primary Key: id (uuid) βββ Risk: βΉοΈ Content data
-
orders βββ Columns: id, user_id, total, status, items, created_at βββ Primary Key: id (uuid) βββ Risk: π΄ Contains financial/transaction data
-
products βββ Columns: id, name, description, price, stock, image_url βββ Primary Key: id (uuid) βββ Risk: βΉοΈ Public catalog data
-
settings βββ Columns: id, key, value, updated_at βββ Primary Key: id (uuid) βββ Risk: β οΈ May contain sensitive configuration
-
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.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.
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 access
-
supabase-audit-rls β Verify RLS policies
-
supabase-audit-rpc β Check exposed functions