// docs / baas security / supabase service role exposure
Chiave di service-role Supabase esposta in JavaScript: cosa significa e come trovarla
La chiave di service-role Supabase è la chiave master del tuo database. Chiunque la possegga bypassa la sicurezza a livello di riga, può leggere ogni colonna di ogni tabella e può scrivere o cancellare ciò che vuole. È progettata per vivere esclusivamente nel codice lato server — mai nel browser. Quando uno strumento di codifica IA la spedisce nel bundle JavaScript, il tuo database è, in effetti, pubblico. Questo articolo spiega la forma del JWT che identifica una chiave trapelata, i tre pattern di strumenti IA che producono il leak, cosa fare nella prima ora dopo la rilevazione e come scansionare automaticamente prima degli utenti.
Cos'è la chiave di service-role
Supabase emette due chiavi distinte per ogni progetto: la chiave anon (chiamata anche chiave pubblicabile nei progetti più recenti) e la chiave service_role. Entrambe sono JSON Web Token firmati dal segreto JWT del tuo progetto. La differenza è il claim role incorporato nel payload del JWT — anon per la chiave pubblica, service_role per la chiave master. PostgREST, Supabase Storage e Supabase Auth tutti passano in modalità bypassa-tutto quando vedono il claim service_role.
Decodifica qualsiasi chiave Supabase su jwt.io e guarda il payload. La forma di un JWT di service-role è inconfondibile:
Payload decodificato di un JWT di service-role (mostrato come blocco evidenziato sotto).
{
"iss": "supabase",
"ref": "[project-ref]",
"role": "service_role",
"iat": 1700000000,
"exp": 2000000000
}I progetti Supabase più recenti emettono chiavi tipo segreto con il prefisso sb_secret_ invece di un JWT. Il comportamento è identico — qualsiasi cosa che porti sb_secret_ in un bundle pubblico è ugualmente catastrofica.
Come gli strumenti di codifica IA fanno trapelare la chiave di service-role
Abbiamo visto gli stessi tre pattern in migliaia di app vibe-coded. Ciascuno inizia con uno sviluppatore che chiede aiuto a uno strumento IA e finisce con la chiave di servizio inline in un bundle.
Pattern 1: singolo file .env con prefisso NEXT_PUBLIC_
Lo sviluppatore chiede allo strumento IA di "configurare Supabase" e accetta un singolo .env con entrambe le chiavi. Lo strumento IA — addestrato su un corpus dove la maggior parte delle variabili d'ambiente sono esposte via NEXT_PUBLIC_* — prefissa entrambe con NEXT_PUBLIC_. Next.js incorpora tutto ciò che corrisponde a quel prefisso nel bundle client al momento del build. Pubblica su Vercel, e la chiave di servizio è in main.[hash].js.
Pattern 2: chiave sbagliata nella chiamata createClient
Lo sviluppatore incolla entrambe le chiavi in un file config.ts generato dall'IA, e l'IA popola per errore la chiamata createClient() lato browser con process.env.SUPABASE_SERVICE_ROLE_KEY. Il build tira la variabile, e il JWT atterra nel bundle.
Pattern 3: chiave service-role hardcoded negli script di seed
Lo sviluppatore chiede allo strumento IA di scrivere uno script che popola il database. L'IA hardcoda la chiave di service-role direttamente nel file (invece di leggere dall'ambiente), committa il file nel repository, e il repo pubblico GitHub o la rotta /scripts/seed.js dell'app deployata ora serve la chiave.
Come il bundle scan FixVibe rileva il leak
Il check segreti-nel-bundle di FixVibe scarica ogni file JavaScript referenziato dall'app deployata — entry chunk, chunk lazy-loaded, web worker, service worker — e li passa attraverso un rilevatore che decodifica qualsiasi cosa corrisponda alla forma JWT (eyJ[base64-header].eyJ[base64-payload].[signature]). Se il payload decodificato contiene "role": "service_role", la scansione lo segnala come risultato critico con il percorso del file e la linea esatta dove appare la chiave. Lo stesso check rileva anche il pattern più recente sb_secret_* per prefisso.
La scansione non si autentica mai con la chiave scoperta. Identifica la forma e segnala il leak — usare la chiave per dimostrare l'exploitability sarebbe accesso non autorizzato al tuo database. La prova è nel payload del JWT stesso.
Rilevata — cosa fare nella prima ora
Una chiave di service-role trapelata è un'emergenza in produzione. Assumi che la chiave sia stata raccolta — gli attaccanti monitorano i bundle pubblici in tempo reale. Tratta il database come compromesso finché non hai ruotato la chiave e auditato l'attività recente.
- Ruota la chiave immediatamente. Nella dashboard Supabase, vai a Project Settings → API → Service role key → Reset. La vecchia chiave viene invalidata in secondi. Qualsiasi codice lato servizio che usa la chiave deve essere aggiornato e rideployato prima che la rotazione abbia effetto.
- Audita l'attività recente del database. Apri Database → Logs nella dashboard. Filtra sugli ultimi 7 giorni. Cerca query
SELECT *insolite contro tabelle con PII, istruzioniUPDATEoDELETEgrandi e richieste da IP fuori dalla tua infrastruttura conosciuta. Supabase registra l'headerx-real-ipsu ogni richiesta. - Controlla gli oggetti di storage. Visita Storage → Logs e rivedi i download recenti di file. Una chiave service-role trapelata dà anche accesso bypassa-tutto ai bucket privati.
- Rimuovi la chiave dal version control. Anche dopo la rotazione, lasciare il JWT nella tua storia git significa che è scopribile nel repo pubblico. Usa
git filter-repoo BFG Repo-Cleaner per pulirlo dalla storia, poi force-push (avvisa prima i collaboratori). - Riscansiona dopo la correzione. Esegui una nuova scansione FixVibe contro l'app rideployata. Il risultato segreti-nel-bundle dovrebbe scomparire. Conferma che nessun JWT
service_rolee nessuna stringasb_secret_*rimanga in alcun chunk.
Prevenire il leak fin dall'inizio
La correzione strutturale è disciplina di nomenclatura più guardrail a livello di strumento:
- Non prefissare mai la chiave di servizio con
NEXT_PUBLIC_*,VITE_*o qualsiasi altro prefisso di inlining nel bundle. La convenzione di nomenclatura è il confine — ogni framework la rispetta. - Tieni la chiave di servizio fuori dal
.envsulla macchina dello sviluppatore del tutto. Leggila da un secret manager (Doppler, Infisical, variabili d'ambiente cifrate Vercel) al deploy, mai committarla localmente. - <strong>Mark every Supabase client construction with explicit context.</strong> Files named <code>supabase/browser.ts</code> use the anon key; files named <code>supabase/server.ts</code> use the service-role key with <code>import 'server-only'</code> at the top. The <code>server-only</code> import causes a build error if a client component tries to consume the module.
- <strong>Add a pre-commit hook that greps for JWT-shaped strings.</strong> <code>git diff --staged | grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'</code> catches both anon and service tokens before they leave your machine.
- Aggiungi un gate CI che scansiona l'output di build. Dopo
next build, fai grep dell'output.next/static/chunks/per la stringaservice_role. Fai fallire il build se qualcosa corrisponde.
# Pre-commit hook: refuse any staged JWT-shaped string.
git diff --staged \
| grep -E 'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+' \
&& echo "JWT detected in staged changes — refusing commit" \
&& exit 1
# CI gate: fail the build if "service_role" shipped to the static bundle.
grep -RE 'service_role|sb_secret_' .next/static/chunks/ \
&& echo "Service-role credential leaked into bundle" \
&& exit 1Domande frequenti
Quanto velocemente gli attaccanti trovano davvero chiavi di service-role Supabase trapelate?
Gli scanner di bundle pubblici setacciano i nuovi deploy in minuti. I ricercatori hanno documentato exploit funzionanti contro nuovi progetti Supabase in meno di un'ora dal primo deploy. Tratta qualsiasi esposizione di service-role come una finestra di 60 minuti, non di 60 giorni.
Ruotare la chiave basta, o devo assumere l'esfiltrazione di dati?
La rotazione invalida la chiave trapelata ma non annulla i dati già estratti. Se le tue tabelle contengono PII, dati di pagamento o qualsiasi dato regolato, potresti avere un obbligo di notifica sotto GDPR (72 ore), CCPA o HIPAA. Audita i log e consulta un consulente legale se l'audit mostra accessi sospetti.
RLS può proteggermi se la chiave di service-role trapela?
No. La sicurezza a livello di riga viene completamente bypassata dal claim service_role. È by design — la chiave esiste precisamente per permettere al codice backend di saltare RLS per operazioni admin. La mitigazione è assicurarsi che la chiave non raggiunga mai un contesto dove un attaccante possa leggerla.
Si applica al nuovo modello chiave pubblicabile / segreta Supabase (<code>sb_publishable_</code> / <code>sb_secret_</code>)?
Sì — classe di rischio identica. La chiave sb_secret_* è il nuovo formato chiave segreta che sostituisce il JWT di service-role per i progetti più recenti. Qualsiasi cosa che porti sb_secret_* in un bundle è altrettanto catastrofica di un JWT di service-role trapelato. Il rilevatore segreti-nel-bundle di FixVibe rileva entrambe le forme.
E la chiave anon / pubblicabile — è sicura nel bundle?
Sì, by design. La chiave anon è destinata a vivere nel browser ed è ciò che usa ogni client web Supabase. La sua sicurezza dipende interamente dal fatto che RLS sia correttamente configurato su ogni tabella pubblica. Vedi l'articolo Scanner RLS Supabase per cosa controllare.
Prossimi passi
Esegui una scansione FixVibe contro la tua URL di produzione — il check segreti-nel-bundle è gratuito, senza registrazione, e segnala esposizioni di service_role in meno di un minuto. Abbinalo all'articolo Scanner RLS Supabase per verificare che lo strato RLS stia facendo il suo lavoro, e la Checklist di sicurezza dei bucket Supabase Storage per bloccare l'accesso ai file. Per il contesto sul perché gli strumenti IA generano questa classe di leak così affidabilmente, leggi Perché gli strumenti di codifica IA lasciano lacune di sicurezza.
