DEV Community

Perufitlife
Perufitlife

Posted on • Originally published at apify.com

I shipped a public Apify actor that scans Supabase projects for RLS leaks (took 90 min, found a 895-record leak on the first real test run)

Just shipped a new public Apify actor: Supabase RLS Security Scanner.

What it does: paste your Supabase URL + anon key, get back a JSON report (plus a pretty HTML report) listing every table that's anonymously readable, with row counts and a curl reproducer for each finding.

Why this exists: the Supabase anon key is meant to be public — it ships in your frontend. The only thing keeping your tables private should be Row-Level Security. Across the 30 Supabase projects I scanned this week, ~10% had RLS forgotten on at least one user-data table (profiles, users, accounts, etc.). One I scanned this morning had 895 staff records with email + phone exposed to anyone with the public anon key.

What it costs: free to run on Apify free plan (cheap Apify compute). I'll publish per-scan pricing in the next update once the actor has 50+ runs of validation.

What it does NOT do: never reads row contents. Uses Prefer: count=exact + Range: 0-0 to confirm a leak exists without touching the data.

# Use it via API:
curl -X POST "https://api.apify.com/v2/acts/renzomacar~supabase-rls-scanner/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN"   -H "Content-Type: application/json"   -d '{
    "supabaseUrl": "https://YOUR-PROJECT.supabase.co",
    "anonKey": "eyJ...your-anon-key...",
    "outputFormat": "both"
  }'
Enter fullscreen mode Exit fullscreen mode

Or the open-source CLI version (free, runs entirely on your machine):

npx @perufitlife/supabase-security --discover --url YOUR_URL --key YOUR_ANON_KEY
Enter fullscreen mode Exit fullscreen mode

Output excerpt from a real scan I ran this morning:

{
  "findings": [
    {
      "table": "staff",
      "count": 895,
      "severity": "critical",
      "sensitiveColumns": ["email", "phone"],
      "reproducer": "curl '.../rest/v1/staff?select=*' -H 'apikey: ...' -H 'Prefer: count=exact' -H 'Range: 0-0' -I"
    }
  ],
  "summary": {
    "total_anon_readable": 3,
    "total_exposed_records": 895
  }
}
Enter fullscreen mode Exit fullscreen mode

What I'm using this for:

  1. My weekly scan servicerls-monitor.vercel.app ($29/mo) runs this against your project every week, alerts you the second a new leak shows up.

  2. Free responsible-disclosure work — I'm offering free scans to the first 20 r/Supabase folks who DM me their URL this weekend (reddit post here). Inbound only — I don't scan projects without explicit permission from the owner.

  3. Sister scanners are coming — Firebase, PocketBase, Appwrite, and Nhost versions all live as npm CLIs (@perufitlife on npm); the Apify-actor versions are next.

If this saves you from a real leak, please leave a review on the Apify store page. That's the engine that keeps me prioritizing this work.

Open-source repo + docs: github.com/Perufitlife/supabase-security-skill.

— Renzo

Top comments (0)