FixVibe

// docs / baas security / supabase rls scanner

Scanner RLS Supabase: trova tabelle con sicurezza a livello di riga mancante o difettosa

La sicurezza a livello di riga (RLS) è l'unica cosa che sta tra i dati dei tuoi clienti e Internet quando metti in produzione un'applicazione supportata da Supabase. Gli strumenti di codifica IA generano codice in forma di RLS che compila, viene spedito e perde dati silenziosamente — tabelle create senza RLS abilitato, policy che leggono ma non restringono mai, predicati che confrontano una colonna con sé stessa. Questo articolo mostra cosa può dimostrare uno scanner RLS Supabase dall'esterno, le quattro forme di RLS difettosa che compaiono nelle app vibe-coded e come scansionare il tuo stesso deployment in meno di un minuto.

Cosa può dimostrare una scansione RLS esterna

A passive RLS scan looks at your Supabase project the way an anonymous visitor would. It uses only the publishable anon key — the same key your browser uses — and never authenticates as a user or touches service-role privileges. Anything it can see, an unauthenticated attacker on the internet can see.

Da fuori del database, uno scanner può confermare quanto segue con alta confidenza:

  • RLS è disabilitato su una tabella. PostgREST restituisce righe per un SELECT anonimo quando RLS è spento o quando una policy lo permette. Entrambi i casi sono un risultato.
  • Il ruolo anonimo può elencare le tabelle. Un GET /rest/v1/ con la chiave anon restituisce lo schema OpenAPI per ogni tabella su cui il ruolo anon ha un qualsiasi privilegio. Le app generate da IA spesso concedono USAGE sullo schema e SELECT su ogni tabella, esponendo la mappa completa dello schema anche quando RLS nega le letture vere e proprie.
  • Read access does not establish write safety. A passive scan cannot prove that INSERT, UPDATE, or DELETE policies protect every user and tenant. Review write policies and test them with isolated fixtures under the intended roles.
  • La chiave di service-role è nel bundle del browser. Adiacente a RLS: se uno scanner trova SUPABASE_SERVICE_ROLE_KEY o qualsiasi JWT con role: service_role nel bundle JavaScript, RLS è irrilevante — chi possiede quella chiave bypassa ogni policy.

Cosa non può dimostrare una scansione esterna

Sii onesto sui limiti dello scanner. Una scansione RLS esterna non può leggere la tua tabella pg_policies, i file di migrazione o il predicato esatto di alcuna policy. Inferisce dal comportamento black-box, il che significa che a volte segnalerà un risultato che si rivela essere dato pubblico intenzionale (una tabella newsletter marketing, un catalogo prodotti pubblico). Il report FixVibe li contrassegna come confidenza media quando lo scanner non può disambiguare l'intento — rivedi il nome della tabella e decidi.

Le quattro forme di RLS difettosa che producono gli strumenti IA

When you point Cursor, Claude Code, Lovable, or Bolt at Supabase, the same four broken-RLS patterns come up again and again. Each one passes type-check, compiles, and ships:

Forma 1: RLS mai abilitato

The most common failure mode. The migration creates the table but the developer (or the AI tool) forgets ALTER TABLE ... ENABLE ROW LEVEL SECURITY. PostgREST happily serves the entire table to anyone with the anon key. Fix: ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;, then add a policy per command. Enabling RLS with no policies denies all access through the API; the policies decide who gets in.

sql
ALTER TABLE public.[name] ENABLE ROW LEVEL SECURITY;

Forma 2: RLS abilitato, nessuna policy

Un fallimento più sottile. RLS è abilitato ma nessuna policy è scritta. Il default in PostgreSQL è nega, quindi gli utenti autenticati non vedono nulla — e lo sviluppatore aggiunge USING (true) per far funzionare l'app, il che permette a tutti di leggere tutto. Correzione: scrivi una policy che limiti per auth.uid(): CREATE POLICY "select_own" ON public.[name] FOR SELECT USING (auth.uid() = user_id); e una policy INSERT/UPDATE/DELETE corrispondente.

sql
CREATE POLICY "select_own"
  ON public.[name]
  FOR SELECT
  USING (auth.uid() = user_id);

Forma 3: policy confronta colonna con sé stessa

Un artefatto da copia-incolla. Lo sviluppatore scrive USING (user_id = user_id) — sempre vero — invece di USING (auth.uid() = user_id). Il type-check passa; la policy permette ogni riga. Correzione: confronta sempre una colonna con una chiamata a funzione (auth.uid(), auth.jwt()->>'org_id', ecc.), mai con sé stessa o con una costante.

Shape 4: Overly permissive write policies

With RLS enabled, a role with no applicable policy is denied by default. A SELECT policy does not itself allow INSERT. Write exposure can arise from a permissive applicable INSERT or ALL policy, disabled RLS, or a role that bypasses RLS. Fix: inspect table privileges and every applicable policy, use ownership-scoped WITH CHECK conditions, and test writes with separate user identities.

Come funziona lo scanner RLS Supabase di FixVibe

FixVibe's Supabase check works from the deployed app, in three steps:

  1. Find the project. FixVibe loads the deployed app and reads the Supabase project URL and public key from the same configuration your browser receives. No guessing, no brute force.
  2. See what is exposed. FixVibe checks which tables the anonymous role can see, without reading row data at this step.
  3. Stage 3 — inspect anonymous read access. The passive check reports observable access to discovered resources. It does not create, update, or delete database rows, and it cannot establish that all write policies or cross-user boundaries are correct.

Each finding ships with the exact request URL, response status, response shape (header-only), and the table name. FixVibe now labels whether the fix belongs in code/config, a provider console, DNS, secret rotation, or manual review so the next step matches who can actually apply it.

Cosa fare quando lo scanner trova qualcosa

Ogni risultato RLS è un'emergenza in produzione. Gli endpoint PostgREST pubblici vengono scansionati dagli attaccanti in minuti. La sequenza di rimedio è meccanica:

  1. Audita ogni tabella. Esegui SELECT schemaname, tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public'; nell'editor SQL di Supabase. Qualsiasi riga con rowsecurity = false è un problema.
  2. Enable RLS on every public table. Default to ENABLE ROW LEVEL SECURITY on every table created — make it a migration template.
  3. Scrivi policy comando per comando. Non usare FOR ALL USING (true). Scrivi policy esplicite per SELECT, INSERT, UPDATE, DELETE — ciascuna limitata a auth.uid() o a una colonna org-id da auth.jwt().
  4. Verifica con un secondo account. Registrati come utente diverso, prova a leggere i record di un altro utente via API REST direttamente. Se la risposta è 200, la policy è rotta.
  5. Re-scan. After applying the fix, re-run a FixVibe scan against the same URL. The Supabase RLS finding should clear.
sql
-- Audit every table for missing RLS. Run in the Supabase SQL editor.
SELECT schemaname, tablename, rowsecurity
FROM   pg_tables
WHERE  schemaname = 'public'
ORDER  BY rowsecurity, tablename;

Come si confronta con altri scanner

La maggior parte degli strumenti DAST generici (Burp Suite, OWASP ZAP, Nessus) non sa cos'è PostgREST. Crawleranno la tua app, ignoreranno il percorso /rest/v1/ e riporteranno sulle pagine HTML che capiscono. Snyk e Semgrep sono strumenti di analisi statica — trovano file di migrazione nel tuo repo con chiamate RLS mancanti, ma non possono dimostrare che il database deployato è mal configurato. FixVibe sta in quel gap: passivo, consapevole del BaaS, focalizzato su ciò che un attaccante non autenticato può dimostrare dalla URL pubblica.

Domande frequenti

Lo scanner leggerà o modificherà i miei dati?

The passive RLS check is read-only. It examines observable anonymous read access and reports limited evidence. It does not perform database write operations or prove that every user and tenant is correctly isolated.

Funziona se il mio progetto Supabase è in pausa o su un dominio personalizzato?

I progetti in pausa restituiscono 503 su ogni richiesta — lo scanner segnala il progetto come irraggiungibile. I domini personalizzati funzionano finché l'app deployata carica ancora l'SDK client Supabase nel browser; lo scanner estrae l'URL del progetto dal bundle in ogni caso.

Cosa succede se la mia chiave anon viene ruotata o la mia chiave pubblicabile cambia?

Riesegui la scansione. Lo scanner estrae di nuovo la chiave dal bundle corrente a ogni esecuzione. La rotazione invalida solo il report precedente, non lo stato delle policy del database.

Lo scanner controlla il nuovo modello di chiave pubblicabile Supabase (sb_publishable_*)?

Sì. Il rilevatore riconosce sia i JWT anon legacy che le più recenti chiavi sb_publishable_* e le tratta identicamente — entrambe sono destinate a essere pubbliche ed entrambe lasciano RLS come unica linea di difesa.

Prossimi passi

Run a free FixVibe scan against your production URL — the Supabase RLS check runs on every plan including the free tier. For a deeper read on what else can leak from a Supabase project, see Supabase service role key exposed in JavaScript and Supabase storage bucket security checklist. For the umbrella view across all BaaS providers, read BaaS misconfiguration scanner.

// scansiona la tua superficie baas

Trova la tabella aperta prima che lo faccia qualcun altro.

Inserisci una URL di produzione. FixVibe enumera i provider BaaS con cui parla la tua app, identifica i loro endpoint pubblici e riporta cosa un client non autenticato può leggere o scrivere. Gratis, senza installazione, senza carta.

  • Piano gratuito — 3 scansioni/mese, senza carta d'iscrizione.
  • Fingerprinting BaaS passivo — nessuna verifica del dominio necessaria.
  • Supabase, Firebase, Clerk, Auth0, Appwrite e altri.
  • Coding-agent prompts where code/config applies, plus provider-console steps for hosted BaaS fixes.
Esegui scansione BaaS gratuita →

nessuna registrazione richiesta

Scanner RLS Supabase: trova tabelle con sicurezza a livello di riga mancante o difettosa · FixVibe