Supabase RLS misconfigurations were the largest cause of public data leaks in 2025. Security researchers use Google dorks plus targeted probes to find projects with RLS disabled. This tutorial runs that audit ethically against your own infrastructure or your bug bounty scope using Scavio SERP.
Prerequisites
- Python 3.10+
- A Scavio API key
- Written bug bounty or in-scope permission
- requests library
Walkthrough
Step 1: Build the dork list
Supabase-hosted domains and REST endpoint patterns.
DORKS = [
'site:supabase.co inurl:/rest/v1/',
'\"supabase.co\" inurl:/rest/v1/ \"anon\"',
'inurl:supabase apikey'
]Step 2: Query Scavio for each dork
Collect all candidate URLs.
import requests, os
API_KEY = os.environ['SCAVIO_API_KEY']
def find_candidates():
hits = []
for d in DORKS:
r = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY},
json={'query': d, 'num_results': 50})
hits += r.json().get('organic_results', [])
return hitsStep 3: Filter to in-scope domains
Drop anything outside your authorized scope.
IN_SCOPE = {'my-company.com', 'my-staging.supabase.co'}
def in_scope(url):
return any(s in url for s in IN_SCOPE)Step 4: Probe the endpoint
A non-intrusive HEAD or GET with anon key reveals RLS state.
def probe(url):
r = requests.get(url, timeout=5)
if r.status_code == 200 and r.json():
return 'RLS LIKELY DISABLED'
return 'OK'Step 5: Report findings
Write a CSV ready for the security channel.
import csv
def report(findings):
with open('rls_audit.csv', 'w') as f:
w = csv.writer(f); w.writerow(['url', 'status'])
for u, s in findings: w.writerow([u, s])Python Example
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
IN_SCOPE = {'my-company.com'}
def audit():
r = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY},
json={'query': 'site:supabase.co inurl:/rest/v1/ my-company', 'num_results': 30})
for hit in r.json().get('organic_results', []):
url = hit['link']
if not any(s in url for s in IN_SCOPE):
continue
probe = requests.get(url, timeout=5)
if probe.status_code == 200 and probe.text.startswith('['):
print(f'ALERT: {url} may have RLS disabled')
audit()JavaScript Example
const API_KEY = process.env.SCAVIO_API_KEY;
const IN_SCOPE = ['my-company.com'];
export async function audit() {
const r = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: 'site:supabase.co inurl:/rest/v1/ my-company', num_results: 30 })
});
const data = await r.json();
for (const hit of data.organic_results || []) {
if (!IN_SCOPE.some(s => hit.link.includes(s))) continue;
const probe = await fetch(hit.link);
if (probe.ok) console.log('ALERT: possible RLS issue at', hit.link);
}
}Expected Output
CSV of in-scope Supabase endpoints flagged as possibly RLS-disabled. Researchers verify manually before reporting. Typical run: 30 dorks, 300 candidates, 5-15 real findings per bounty program.