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"
}'
Or the open-source CLI version (free, runs entirely on your machine):
npx @perufitlife/supabase-security --discover --url YOUR_URL --key YOUR_ANON_KEY
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
}
}
What I'm using this for:
My weekly scan service — rls-monitor.vercel.app ($29/mo) runs this against your project every week, alerts you the second a new leak shows up.
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.
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 (1)
Nice shape on the threat model —
Prefer: count=exact+Range: 0-0to confirm a leak without touching row contents is the kind of detail that decides whether the actor reads as "security tool" vs "exfiltration helper." That one line probably does more for trust than the whole README.Two questions from someone running a different public Apify actor:
Has Apify Store discoverability driven any organic runs for you, or are most still coming from the Reddit/npm side? I shipped a Gmail inbox-analytics actor last weekend (free MIT, similar shape — public actor + companion $9 PDF for the non-self-host path) and the Store page has been about 2 dry runs while dev.to + GitHub READMEs do the actual reach work.
On the per-scan pricing: are you planning to keep the free Apify-CU path open and gate only the SaaS weekly-scan layer, or move runs onto the paid tier once you hit the 50+ validation runs? Curious where the OSS/SaaS line ends up in practice.