Claude
Skills
Sign in
โ† Back

supabase-audit-tables-list

Included with Lifetime
$97 forever

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

Backend & APIs

What this skill does


# 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

```json
{
  "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:
```sql
-- 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

```sql
-- 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

```sql
-- 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

```sql
-- 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:
   ```json
   {
     "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

Related in Backend & APIs