# Supabase Security Audit - Find RLS Leaks Free (`renzomacar/supabase-security-auditor`) Actor

Audit any Supabase project for missing RLS, public tables, dangerous SECURITY DEFINER functions, public storage buckets, and over-permissive policies. Active anon probe confirms live leaks. HTML report with paste-ready fix SQL. Read-only token, never persisted. Free.

- **URL**: https://apify.com/renzomacar/supabase-security-auditor.md
- **Developed by:** [Renzo Madueno](https://apify.com/renzomacar) (community)
- **Categories:** Developer tools
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Supabase Security Auditor

> Scan any Supabase project for security misconfigurations. Get a shareable HTML report with copy-paste fix SQL on every finding.
> No install. No SaaS account. Your token is used only for the run and never stored.

### Why this exists

On **May 30, 2026** Supabase changed its default for new projects: tables in `public` no longer auto-expose to the Data API. On **October 30, 2026** that becomes the enforced default for **all existing projects**.

If you've been on Supabase for more than a few months, you almost certainly have:
- Tables granted CRUD to `anon` by default (because that was the default).
- One or two tables where RLS got missed.
- `SECURITY DEFINER` functions that are technically callable by `anon`.

This actor surfaces all of that in one click. I built it after running it on my own production app and finding **17 publicly readable tables I had no idea about** — `b2b_leads`, `engagement_emails`, internal growth metrics. Anyone with the anon key from the JS bundle could read or delete them.

### What it checks

| ## | Check | Severity |
|---|---|---|
| 1 | Table has RLS disabled and direct anon grants | **CRITICAL** |
| 2 | Table in `supabase_realtime` publication WITHOUT RLS (leak via WebSocket) | **CRITICAL** |
| 3 | `SECURITY DEFINER` function (non-trigger) executable by `anon` | HIGH |
| 4 | Anonymous sign-ins enabled | HIGH |
| 5 | Public storage bucket | HIGH |
| 6 | Default privileges still grant CRUD on future tables | MEDIUM |
| 7 | Auth signups enabled without email confirmation | MEDIUM |
| 8 | Weak password policy (`password_min_length < 8`) | MEDIUM |
| 9 | No CAPTCHA on auth endpoints | MEDIUM |
| 10 | `SECURITY DEFINER` function without `SET search_path` | MEDIUM |
| 11 | RLS-locked table still has direct anon grants (defense-in-depth) | LOW |

### Output

- **HTML report** — self-contained (~25KB Tailwind + Chart.js via CDN). Saved to the run's key-value store under key `REPORT`. URL: `https://api.apify.com/v2/key-value-stores/{storeId}/records/REPORT`. Open in any browser. Includes copy-paste fix SQL on every finding plus an "apply all" SQL bundle.
- **Dataset** — every finding as a structured row (severity, title, target, fix_sql) for filtering/exporting in the Apify console.
- **SUMMARY KV record** — quick numbers for monitoring (counts by severity, total tables/functions/buckets scanned).

### Sample report

The HTML report header shows your project name, region, scan timestamp, a letter grade (A+ → F), and KPI tiles for each severity level. Below that: severity bar chart, every finding as an expandable card, and a single "apply all" SQL bundle at the bottom.

### How to get a Personal Access Token

1. Open https://supabase.com/dashboard/account/tokens
2. Click "Generate new token"
3. Read access is enough for the audit (the actor never writes to your project)

The token is passed as input, used only for this run's Management API queries, and never persisted by the actor.

### Apply the fixes

The actor never modifies your project. To apply fixes:

1. Open the HTML report
2. Review each finding (some `SECURITY DEFINER` functions are intentionally exposed to anon — your decision)
3. Click "Copy all SQL" at the bottom
4. Paste into Supabase Dashboard → SQL Editor
5. Run inside `BEGIN; ... ROLLBACK;` first to verify, then `BEGIN; ... COMMIT;`

For a full agent loop (audit + preview + apply + re-audit) inside Claude Code / Cursor / Cline, see the sibling MCP server: https://github.com/Perufitlife/supabase-security-mcp

### Pricing

Pay per run. The audit completes in 10–60 seconds depending on project size.

### Source

Open source MIT — https://github.com/Perufitlife/supabase-security-skill

### Limits

- Doesn't audit per-object Storage RLS yet (would mean iterating every file)
- Cannot revoke `supabase_admin` default privileges via SQL — that needs the Dashboard toggle. The report tells you so.
- App APIs intentionally exposed to anon (e.g. `get_public_stats()` RPC) appear as findings. You decide which are intentional.
- Alpha. PRs and issues welcome on GitHub.

# Actor input Schema

## `projectRef` (type: `string`):

Your Supabase project reference (the 20-char string in your project URL, e.g. abcdefghijklmnopqrst from https://abcdefghijklmnopqrst.supabase.co).
## `accessToken` (type: `string`):

Supabase Personal Access Token. Create one at https://supabase.com/dashboard/account/tokens (read access is enough for the audit). Token is used only for this run and never stored.
## `outputFormat` (type: `string`):

Choose 'html-report' for a self-contained shareable HTML dashboard with copy-paste fix SQL (saved to KV store as REPORT). 'json' returns raw findings only. 'both' produces both.

## Actor input object example

```json
{
  "outputFormat": "html-report"
}
````

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("renzomacar/supabase-security-auditor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("renzomacar/supabase-security-auditor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call renzomacar/supabase-security-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=renzomacar/supabase-security-auditor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Supabase Security Audit - Find RLS Leaks Free",
        "description": "Audit any Supabase project for missing RLS, public tables, dangerous SECURITY DEFINER functions, public storage buckets, and over-permissive policies. Active anon probe confirms live leaks. HTML report with paste-ready fix SQL. Read-only token, never persisted. Free.",
        "version": "0.1",
        "x-build-id": "WbDHY1KOz3PRCWZDF"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/renzomacar~supabase-security-auditor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-renzomacar-supabase-security-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/renzomacar~supabase-security-auditor/runs": {
            "post": {
                "operationId": "runs-sync-renzomacar-supabase-security-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/renzomacar~supabase-security-auditor/run-sync": {
            "post": {
                "operationId": "run-sync-renzomacar-supabase-security-auditor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "projectRef",
                    "accessToken"
                ],
                "properties": {
                    "projectRef": {
                        "title": "Project Ref",
                        "pattern": "^[a-z]{20}$",
                        "type": "string",
                        "description": "Your Supabase project reference (the 20-char string in your project URL, e.g. abcdefghijklmnopqrst from https://abcdefghijklmnopqrst.supabase.co)."
                    },
                    "accessToken": {
                        "title": "Personal Access Token",
                        "type": "string",
                        "description": "Supabase Personal Access Token. Create one at https://supabase.com/dashboard/account/tokens (read access is enough for the audit). Token is used only for this run and never stored."
                    },
                    "outputFormat": {
                        "title": "Output format",
                        "enum": [
                            "html-report",
                            "json",
                            "both"
                        ],
                        "type": "string",
                        "description": "Choose 'html-report' for a self-contained shareable HTML dashboard with copy-paste fix SQL (saved to KV store as REPORT). 'json' returns raw findings only. 'both' produces both.",
                        "default": "html-report"
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
