Agent Skills

supabase-audit-tables-list

List all tables exposed via the Supabase PostgREST API to identify the attack surface.

Install

npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-audit-tables-list
SKILL.md

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:

  1. They exist in an exposed schema (default: public)
  2. No explicit REVOKE has been done
  3. 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:

  1. Before starting any action → Log the action to .sb-pentest-audit.log
  2. After each table discovered → Immediately update .sb-pentest-context.json
  3. 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)

  1. Update .sb-pentest-context.json with results:

    {
      "tables": {
        "count": 8,
        "list": [ ... ],
        "by_risk": { "high": [], "medium": [], "low": [] }
      }
    }
    
  2. 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
    
  3. 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

Related skills

azure-compliancemicrosoft606KRun Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.firebase-security-rules-auditorfirebase124KAudits Firebase (Firestore, Cloud Storage) security rules for vulnerabilities, privilege escalation, role bypasses, create vs update inconsistencies, resource exhaustion, type safety, size limits, and hasOnly ownership checks. Use when auditing/reviewing rules, running red-team rule assessments, or scoring against auditor checklists. Don't use for Firebase CLI (login, deploy), Auth, Crashlytics, Remote Config, or database queries.browser-fingerprint-auditliarjsdev69KAudit a browser fingerprint for internal contradictions with the liarjs CLI - canvas, WebGL, WebGL2, WebGPU, audio, 220 fonts, WebRTC and timezone probes, scored against the TLS/HTTP/ASN view of the same request. Use when asked to run a browser fingerprint test, see what a fingerprint looks like, check canvas or WebGL fingerprint stability, compare a spoofed profile against a real browser, or find out whether a browser profile is self-consistent.cloudflare-onecloudflare66KDesign, configure, troubleshoot, or review Cloudflare One Zero Trust and SASE deployments. Use cloudflare-one-migrations for migration planning from other vendors.

Search skills and MCP servers

Fuzzy search across 23,137 skills and servers