Las configuraciones erróneas de Supabase RLS fueron la principal causa de filtraciones de datos públicos en 2025. Los investigadores de seguridad utilizan Google Dorks y sondas específicas para encontrar proyectos con RLS deshabilitado. Este tutorial ejecuta una auditoría ética de su propia infraestructura o del alcance de su recompensa de errores utilizando Scavio SERP.
Requisitos previos
- Python 3.10+
- Una clave API de Scavio
- Recompensa por errores por escrito o permiso dentro del alcance
- solicita biblioteca
Guia paso a paso
Paso 1: Crea la lista de idiotas
Dominios alojados en Supabase y patrones de puntos finales REST.
DORKS = [
'site:supabase.co inurl:/rest/v1/',
'\"supabase.co\" inurl:/rest/v1/ \"anon\"',
'inurl:supabase apikey'
]Paso 2: Consulta a Scavio para cada idiota
Recopile todas las URL candidatas.
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 hitsPaso 3: Filtrar a dominios dentro del alcance
Deje caer cualquier cosa fuera de su alcance autorizado.
IN_SCOPE = {'my-company.com', 'my-staging.supabase.co'}
def in_scope(url):
return any(s in url for s in IN_SCOPE)Paso 4: Sondear el punto final
Un HEAD o GET no intrusivo con una clave anónima revela el estado de RLS.
def probe(url):
r = requests.get(url, timeout=5)
if r.status_code == 200 and r.json():
return 'RLS LIKELY DISABLED'
return 'OK'Paso 5: Hallazgos del informe
Escriba un CSV listo para el canal de seguridad.
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])Ejemplo en Python
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()Ejemplo en JavaScript
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);
}
}Salida esperada
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.