Vai al contenuto

Basi della sicurezza

Come ruotare una chiave service_role Supabase trapelata

Supabase dice di chiudere prima la falla. Altre guide dicono di ruotare subito. Quale sia giusto dipende da dove è finita la tua chiave service_role.

Vlad Tkachenko9 min di lettura
Un lucchetto e accanto due chiavi identiche, disegnate della stessa misura, una chiara e una sbiadita.

In breve

  • Se la tua chiave service_role di Supabase è nel JavaScript che un browser scarica, ruotala prima di sistemare qualsiasi altra cosa. La copia già in circolazione non scade.
  • Se è arrivata solo a un repository privato o a un log, chiudi prima la sorgente, altrimenti la chiave nuova segue la vecchia al deploy successivo.
  • Una vecchia chiave service_role non si può ruotare affatto. Invalidarla significa creare le nuove chiavi sb_secret_, spostarci sopra la tua app e disattivare la vecchia coppia con un interruttore che le riguarda entrambe.

Qualcuno ti ha detto che la tua chiave service_role di Supabase si trova nella tua app, dove chiunque può leggerla. Prima di cambiare qualsiasi cosa, assicurati che sia davvero quella la chiave che hanno trovato: la nostra scansione gratuita legge il tuo sito in produzione come lo leggerebbe uno sconosciuto e ti dice quale chiave Supabase vede lì davvero. Senza account e senza installare nulla.

Il consiglio che segue una scoperta del genere è quasi sempre una parola sola: ruotala. Poi vai a cercare come si fa, e le fonti si contraddicono. La documentazione di Supabase apre la sua guida alla rotazione dicendoti di correggere la causa della falla prima di iniziare. Una mezza dozzina di guide di terze parti ti dice di ruotare subito e fare domande dopo.

Ecco la parte che nessuna delle due scrive: hanno ragione entrambe, in situazioni diverse, e la domanda che le separa è dove sia finita la chiave.

Una cosa da mettere in chiaro prima di tutto. Cancellare la chiave dal tuo codice toglie la tua copia dal mazzo. Ruotarla cambia la serratura. Solo la seconda raggiunge le copie che altri hanno già.

È davvero la chiave service_role?

In un progetto recente rispondono i primi caratteri. sb_secret_ all'inizio è quella segreta. sb_publishable_ è la chiave che deve stare nella tua app, e trovarla lì non è affatto una scoperta.

Accertatene prima di fare qualcosa di drastico, perché la chiave che si trova in un'app fatta in vibe coding è di solito quella che ci deve stare.

I progetti più vecchi rilasciano un'altra coppia, anon e service_role, e le due si assomigliano moltissimo: stesso formato, stessa lunghezza, nessun prefisso da leggere. La sezione centrale di una di quelle chiavi non è cifrata affatto. Si decodifica in qualche riga di testo semplice, e una di quelle righe indica il ruolo. Quali chiavi API sono sicure nel frontend percorre entrambi i controlli.

Il motivo per esserne sicuri è che il caso è più raro di quanto suggeriscano gli avvertimenti. Abbiamo scansionato 30.998 app in vibe coding ad agosto 2026 e abbiamo trovato una chiave service_role pubblicata in 3 di esse. Una chiave API di Google, di solito innocua e spesso limitata a un dominio, è comparsa in 1.142. Il conteggio completo è qui.

Ruotare prima o chiudere prima la falla?

Dipende dal fatto che la chiave sia già pubblica, e la linea tra i due casi è netta.

Se la chiave è nel JavaScript che i tuoi visitatori scaricano, adesso è pubblica. Chiunque abbia caricato il tuo sito mentre era attiva ne ha una copia, e ce l'ha anche ogni crawler automatico che stava cercando esattamente quella stringa. Niente di quello che cambi nel tuo codice raggiunge quelle copie. Prima ruota, poi chiudi la sorgente.

Se è arrivata solo a un repository privato, a un file di log, a una variabile di CI o a una chat, l'esposizione è limitata. Se qui ruoti per prima cosa, lo farai due volte, perché il deploy successivo rimette fuori il valore vecchio da qualunque cosa lo producesse e la chiave nuova segue la vecchia. Chiudi la sorgente, poi ruota.

La guida di Supabase è scritta per il secondo caso. Le guide urgenti sono scritte per il primo. Se stai leggendo questo perché uno scanner ha trovato la chiave sul tuo URL in produzione, sei nel primo caso.

Gli stessi due compiti, in ordine opposto. A decidere è se la copia trapelata è già in giro per il mondo.

Come ruotare una chiave segreta di Supabase

Se il tuo progetto ha chiavi sb_secret_, è una faccenda da pannello e senza interruzione di servizio.

Un progetto può tenere più di una chiave segreta alla volta, ognuna con il suo nome, ed è questo che rende l'operazione sicura: aggiungi la nuova prima di togliere la vecchia, quindi nel mezzo non c'è niente di rotto.

  1. Apri il progetto, vai su Settings → API Keys e crea una nuova chiave segreta.
  2. Mettila ovunque si usasse la vecchia, e dovrebbe essere tutto su un server: edge function, webhook, job pianificati, un backend tuo. Dove stanno quei valori se non hai mai aperto quella pagina.
  3. Fai il deploy, poi passa in rassegna le parti della tua app che leggono e scrivono dati. Una chiave segreta sbagliata fallisce in modo rumoroso e immediato, che è il caso buono.
  4. Solo allora cancella la chiave compromessa.

Il passo 4 è permanente. Supabase cancella una chiave segreta sul serio: nessun annulla, nessuna riattivazione, nessuna copia parcheggiata che tu possa recuperare. Per questo va per ultimo.

Cancellare una chiave segreta non fa uscire i tuoi utenti. Una chiave API dice quale applicazione sta interrogando il tuo database, e il token di sessione di un visitatore dice quale utente è. Il secondo viene verificato contro la chiave di firma del progetto, ed è un valore separato che non hai toccato.

Perché una vecchia chiave service_role di Supabase non si può ruotare

Perché non esiste un pulsante per farlo. La nota di troubleshooting di Supabase dice che la rotazione diretta dei vecchi segreti anon, service_role e JWT non è più supportata, e ti rimanda alle chiavi nuove.

Invalidare una vecchia chiave service_role trapelata è quindi una migrazione e non una rotazione:

  1. Crea le chiavi nuove. Questo aggiunge sb_publishable_ e sb_secret_ accanto alla vecchia coppia. I due sistemi funzionano insieme e non si rompe niente.
  2. Sposta il frontend sulla chiave pubblicabile. In Lovable o Bolt di solito è un valore nelle impostazioni del progetto e non una riga di codice.
  3. Sposta ogni uso lato server sulla chiave segreta.
  4. Disattiva le vecchie chiavi nelle impostazioni del progetto.

Il passo 4 è un solo interruttore e riguarda entrambe le vecchie chiavi. anon e service_role sono JWT firmati con lo stesso segreto, quindi l'interruttore che revoca l'una revoca anche l'altra, e un frontend che porta ancora la vecchia chiave anon smette di funzionare nel momento in cui lo premi. Per questo il passo 2 viene prima.

Disattivare le vecchie chiavi è un solo comando per entrambe. La chiave anon che la tua app sta usando se ne va insieme alla chiave service_role che vuoi invalidare.

La disattivazione è reversibile, ed è l'unica buona notizia di questa sezione: se qualcosa che avevi dimenticato usa ancora una vecchia chiave, puoi riaccenderle mentre la sistemi. Cosa comporta la migrazione lo racconta più per esteso.

Da dove è trapelata la chiave, e come chiudere

Tre cause spiegano quasi tutto, e tutte e tre stanno dentro il tuo progetto.

Un prefisso VITE_ o NEXT_PUBLIC_. Non sono un'impostazione di sicurezza che qualcuno ha dimenticato di attivare. Sono un'istruzione per la build: metti questo valore nel bundle. Una variabile chiamata VITE_SUPABASE_SERVICE_ROLE_KEY è stata compilata nel tuo JavaScript di proposito, da uno strumento che ha fatto esattamente quello che gli era stato detto.

Un valore incollato dritto in un componente. Nessun prefisso di mezzo e nessun file .env, solo la chiave posata in una riga di codice perché era il modo più veloce di far restituire qualcosa a una query.

Lavoro che sta su un server. Cancellare un account, scrivere in una tabella in cui i tuoi utenti non possono scrivere, leggere righe di tutti quanti. Alla chiave si è ricorsi perché il browser non poteva fare quel lavoro, e la soluzione è spostare il lavoro: una edge function, una rotta serverless, qualsiasi cosa che i tuoi visitatori non scarichino.

Come faccio a sapere se qualcuno l'ha usata?

Di solito non puoi esserne certo. Quello che puoi fare è restringere la finestra e guardarci dentro.

La finestra si apre con il deploy che ha pubblicato la chiave per la prima volta e si chiude quando l'hai disattivata. Il tuo progetto Supabase tiene log sia per l'API sia per il database, ed è su quell'intervallo che vanno filtrati. Quello che cerchi sono letture e scritture che non sai spiegare: richieste a tabelle che la tua app non tocca mai, traffico in ore in cui nessuno la stava usando, cancellazioni che non ha fatto nessuno.

Poi controlla i dati stessi. Conteggi di righe rispetto a quello che ti aspetti, i tuoi stessi record di account, qualsiasi cosa con una marca temporale che si è mossa mentre nessuno lavorava. Un messaggio all'assistenza su dati cambiati da soli è il modo in cui la maggior parte di questi casi viene davvero scoperta, e arriva settimane dopo.

Una chiave service_role non raggiunge il tuo fornitore di pagamenti né il tuo invio di email. Vale comunque la pena sapere se era l'unica chiave nel tuo bundle, perché quelle che spendono soldi trapelano per la stessa strada: cosa pubblicavano 30.998 app.

Controlla la tua app in produzione prima di darla per chiusa

Carica il sito in una finestra privata, apri il JavaScript che il browser ha scaricato e cercaci dentro il valore vecchio. Poi cerca quello nuovo, che lì non dovrebbe esserci nemmeno lui.

Due cose rendono utile questo controllo a mano. Una build può servire un bundle in cache ancora per un po' dopo il deploy, quindi il file che riceve un visitatore non è sempre quello che hai appena costruito. E una chiave può stare in più di un posto: un secondo punto di ingresso, un service worker, una vecchia build ancora servita da un percorso a cui nessuno rimanda.

La nostra scansione gratuita fa questa parte da fuori, sull'URL che i tuoi visitatori usano davvero, e decodifica una chiave Supabase quanto basta per leggerne il ruolo, quindi una chiave pubblicabile torna con una spunta. Ci mette una ventina di secondi e non richiede un account: scansiona la tua app.

Cosa fare adesso

Cosa fare

  • Conferma prima la chiave. sb_secret_ davanti, oppure "role": "service_role" dentro una più vecchia. Una chiave pubblicabile nel tuo frontend non è una scoperta.
  • Se è nel bundle che i tuoi visitatori scaricano, ruotala prima di toccare il codice. Modificare la tua app non raggiunge le copie già in circolazione.
  • Se è trapelata solo a un repository, a un log o a una chat, chiudi prima la sorgente, così il prossimo deploy non rimette subito fuori la chiave nuova.
  • In un progetto recente: crea una seconda chiave segreta, spostaci sopra il codice del server, fai il deploy e poi cancella la vecchia. La cancellazione è definitiva.
  • In un progetto vecchio non c'è un pulsante di rotazione. Crea le chiavi nuove, spostaci sopra frontend e server, poi disattiva la vecchia coppia con l'unico interruttore che le riguarda entrambe.
  • Dopo, cerca dentro il tuo bundle in produzione. Una build in cache può servire il valore vecchio ancora per un po' dopo il deploy.

Una chiave service_role legge e scrive ogni riga del tuo database. La versione peggiore di questa storia finisce con una tabella vuota, e se quelle righe tornano dipende da cosa stavi salvando prima che succedesse tutto questo.

FAQ

Ruotare la chiave rompe la mia app in produzione?

No, se rispetti l'ordine. In un progetto con le chiavi nuove aggiungi una seconda chiave segreta, ci sposti sopra il codice del tuo server, fai il deploy e solo allora cancelli la vecchia, così non esiste mai un momento senza una chiave funzionante. In un progetto vecchio il rischio è un altro: disattivare la vecchia coppia disattiva anche la chiave anon che usa il tuo frontend, quindi la tua app si ferma se non è già passata alla chiave pubblicabile quando premi quell'interruttore.

Posso ruotare le vecchie chiavi anon e service_role?

No. La documentazione di troubleshooting di Supabase dice che la rotazione diretta dei vecchi segreti anon, service_role e JWT non è più supportata. Invalidare una vecchia chiave trapelata significa creare le nuove chiavi sb_publishable_ e sb_secret_, spostarci sopra la tua app e il codice del tuo server, e poi disattivare la vecchia coppia nelle impostazioni del progetto.

Devo cancellare la vecchia chiave o disattivarla?

Non puoi scegliere, perché i due sistemi di chiavi si comportano in modo diverso. Una chiave sb_secret_ recente viene cancellata, in modo permanente, senza alcun modo di recuperarla. La vecchia coppia si disattiva invece, e la disattivazione è reversibile: se qualcosa che avevi dimenticato usa ancora una vecchia chiave, puoi riaccenderle mentre la sistemi.

Come faccio a sapere se qualcuno l'ha usata?

Di solito non puoi esserne certo. Riducilo piuttosto a una finestra temporale: la chiave è stata utilizzabile dal deploy che l'ha pubblicata per la prima volta fino al momento in cui l'hai disattivata. Filtra i log dell'API e del database del tuo progetto Supabase su quell'intervallo e cerca letture e scritture che non sai spiegare, poi controlla i dati stessi: conteggi di righe e marche temporali che non corrispondono a nulla che tu abbia fatto.

Devo ruotare anche la chiave anon?

In un progetto vecchio non puoi scegliere: disattivare la vecchia coppia porta via entrambe le chiavi in una volta, quindi il tuo frontend ha bisogno della nuova chiave pubblicabile prima che tu prema l'interruttore. In un progetto recente la chiave pubblicabile è pensata per essere pubblica e non c'è motivo di toccarla. Quello che vale la pena controllare in entrambi i casi è Row Level Security, perché è l'unica cosa che sta tra una chiave pubblicabile e tutto il tuo database.

Scritto da

Vlad Tkachenko

Fondatore di Reeve

Passo le giornate a guardare app costruite con Lovable, Bolt, v0, Cursor e Replit, e la breve lista di errori che vi ricompaiono di continuo.

Altro sull'autore

Da leggere dopo

Tutti gli articoli

Non sai come sta messa la tua app?

Esegui una scansione gratuita e ottieni un voto chiaro da A a F in una ventina di secondi. Senza account e senza carta.

Scansiona la tua app gratis

Controllo esterno automatizzato, non un audit completo. L'assenza di risultati non è una garanzia di sicurezza.