Vai al contenuto

Basi della sicurezza

Supabase "permission denied for table": il grant mancante

Dal 30 ottobre una nuova tabella di Supabase risponde "permission denied for table" finché non concedi l'accesso. Il grant della mail è metà della soluzione.

Vlad Tkachenko10 min di lettura
Una fila di porte che danno su tabelle di un database. Le più vecchie sono aperte su righe illuminate, e la più nuova, in fondo, è chiusa.

In breve

  • Dal 30 ottobre 2026 una nuova tabella del tuo progetto Supabase risponde "permission denied for table" finché qualcuno non le concede l'accesso. Le tabelle che hai già continuano a funzionare esattamente come oggi.
  • Un grant decide se una richiesta arriva a una tabella. Row Level Security continua a decidere quali righe si porta via. Dare ad anon l'accesso a una tabella senza regole rende ogni riga leggibile da chiunque.
  • Il cambiamento non chiude nulla che sia già aperto. Controlla cosa può leggere oggi uno sconosciuto, e di nuovo dopo ogni tabella che aggiungi.

Se la tua app gira su Supabase, probabilmente ti è arrivata una mail sul 30 ottobre. Dice che per le tabelle che hai già non cambia nulla, e subito dopo ti consegna tre istruzioni SQL. Oppure è già novembre: hai chiesto a Lovable, Bolt o Cursor una funzione nuova, la schermata nuova è rimasta vuota, e da qualche parte nella console c'è un messaggio che dice permission denied for table. Sono lo stesso cambiamento di Supabase, visto dai due lati della data.

Ecco la parte che la mail lascia fuori: l'SQL che ti mostra è metà della soluzione. Esegui quella metà da sola, sulla tabella sbagliata, e la tua app torna a funzionare mentre la tabella nuova consegna le sue righe a chiunque le chieda.

Cosa significa "permission denied for table" in Supabase?

Significa che il tipo di visitatore che fa la richiesta non ha alcun accesso a quella tabella, quindi il database l'ha rifiutata prima di guardare una sola riga.

Supabase assegna ogni richiesta a un ruolo, cioè il tipo di visitatore da cui arriva. anon è qualcuno che non ha effettuato l'accesso. authenticated è qualcuno che l'ha fatto. service_role è il tuo codice lato server che usa la chiave segreta. Un grant è l'istruzione che dà a uno di quei ruoli l'accesso a una tabella in Postgres, il database su cui gira Supabase. Niente grant, niente accesso, qualunque altra cosa tu abbia scritto.

Quando manca il grant, Supabase risponde così, di solito come un 401 o un 403:

{
  "code": "42501",
  "message": "permission denied for table comments",
  "hint": "Grant the required privileges to the current role with: GRANT SELECT ON public.comments TO anon;"
}

Il suggerimento è la parte utile. Nomina il ruolo che è stato respinto e l'istruzione esatta che lo farebbe entrare.

Pensa a ogni tabella come a una stanza. Il grant è la porta, e c'è una porta diversa per ogni ruolo. Row Level Security, le regole per riga che forse hai già incontrato, decide quali cassetti un visitatore può aprire una volta dentro. "Permission denied for table" vuol dire che qualcuno è fermo davanti a una porta chiusa. Non è mai arrivato fino alle tue regole.

Cosa cambia il 30 ottobre?

Le nuove tabelle nello schema public, la cartella di tabelle che il tuo builder usa se non gli dici altro, cominciano ad arrivare con le porte chiuse.

Finora Supabase apriva automaticamente tutte e tre le porte su ogni nuova tabella: leggere, aggiungere, modificare e cancellare, per anon, authenticated e service_role allo stesso modo. Una tabella era raggiungibile dalla tua app dal momento in cui esisteva, e le tue regole di Row Level Security erano l'unica cosa fra uno sconosciuto e le sue righe. Il changelog di Supabase spiega il motivo senza giri di parole: agenti e piattaforme di IA oggi creano tabelle senza che nessuno riveda la modifica, e i grant automatici esponevano tabelle che "a developer forgot to protect", che qualcuno aveva dimenticato di proteggere.

DataCosa è successo o succede
28 aprile 2026I nuovi progetti potevano rinunciare ai grant automatici al momento della creazione.
30 maggio 2026"Niente grant automatici" ha cominciato a diventare il default per i nuovi progetti.
30 ottobre 2026Anche i progetti esistenti smettono di riceverli.

Se il tuo progetto è stato creato dopo la fine di maggio, potrebbe già funzionare così, perché Supabase ha esteso il nuovo default ai progetti nuovi nelle settimane successive a quella data.

Le tabelle che esistono il 30 ottobre conservano le porte che hanno, compresa una che era aperta agli sconosciuti. Solo le tabelle create dopo partono con la porta chiusa.

Tre dettagli che conviene conoscere prima della data:

  • Solo lo schema public. Storage e l'accesso degli utenti tengono le loro tabelle in schemi propri, storage e auth, e Supabase dice che i loro grant e le loro impostazioni predefinite restano come sono.
  • Anche la chiave segreta viene respinta. I grant automatici coprivano anche service_role, quindi una edge function (codice lato server che Supabase esegue per te) che usa la tua chiave segreta riceve lo stesso errore su una tabella nuova finché service_role non ha un grant tutto suo.
  • Una tabella cancellata e ricreata è una tabella nuova. I grant appartengono alla tabella stessa, e se ne vanno con lei quando viene cancellata. Se il tuo builder ricostruisce una tabella per modificarla, quella ricostruita parte con la porta chiusa.

La mia app si romperà il 30 ottobre?

Non quel giorno. Si rompe la prima volta che qualcosa crea una tabella nuova senza creare anche il grant.

Per la maggior parte di chi legge, quel qualcosa è il builder. Chiedi una sezione commenti. Il builder scrive una migrazione, cioè il file di modifiche al database che esegue per te, e la migrazione crea una tabella comments. Se scrive anche i grant, questo errore non lo vedrai mai. Se non lo fa, la schermata dei commenti non mostra nulla, oppure salvare un commento fallisce, oppure compare un messaggio rosso, a seconda di come la tua app gestisce un errore. Tutte le schermate che avevi già continuano a funzionare.

Supabase pubblica una agent skill per gli strumenti di programmazione con IA che include il passaggio del grant. Se il tuo builder la usi dipende dal tuo builder, quindi l'ipotesi prudente è che la prossima tabella che crea possa arrivare con la porta chiusa.

È sicuro eseguire il GRANT che suggerisce l'errore?

Solo quando la tabella ha già Row Level Security acceso e una regola scritta. Il grant decide chi passa dalla porta. Niente in lui decide quali cassetti apre.

La chiave con cui la tua app fa le sue richieste a Supabase viaggia dentro la tua app, quindi un grant ad anon significa che qualsiasi visitatore, con o senza accesso, può ora chiedere righe a quella tabella. Con una regola al suo posto riceve le righe che la regola permette. Con Row Level Security spento riceve ogni riga della tabella, e nella tua app non cambierà nulla di visibile.

La mail mostra tre grant e si ferma lì. Il changelog di Supabase mostra tre passaggi, e dice di trattarli come un'unica cosa ("treat these three steps as a unit"):

-- 1. chi può raggiungere la tabella
grant select on public.orders to authenticated;
grant select, insert, update, delete on public.orders to service_role;

-- 2. accendere le regole per riga
alter table public.orders enable row level security;

-- 3. la regola vera e propria
create policy "Customers read their own orders"
  on public.orders
  for select
  to authenticated
  using (auth.uid() = user_id);

In quell'esempio non c'è nessuna riga per anon, ed è voluto. Nessuno senza accesso dovrebbe raggiungere una tabella di ordini, quindi la porta per gli sconosciuti resta chiusa, e i clienti autenticati ricevono solo la lettura che serve alla loro schermata. Poi la regola la restringe alle loro righe. Il consiglio di Supabase è di concedere a ogni ruolo il minimo che gli serve. Un grant ad anon ha senso su una tabella le cui righe sono per tutti, come i commenti sotto un post pubblico.

Il grant decide se una richiesta raggiunge la tabella. Le regole dietro decidono quanto si porta via. Una porta aperta senza regole dietro consegna la tabella intera.

Se vuoi vedere da che parte di quel disegno stanno le tue tabelle, la nostra scansione gratuita fa alla tua app online la domanda che farebbe uno sconosciuto, conta le righe che riceverebbe senza scaricarne nessuna, e ci mette circa 20 secondi senza account: scansiona la tua app.

Perché le correzioni di Row Level Security non toccano questo errore

Perché il grant viene controllato per primo. Una richiesta respinta alla porta non arriva mai alle tue regole, quindi cambiare le regole non cambia nulla dell'errore.

Conta perché il codice è condiviso. 42501 è anche quello che Postgres restituisce quando Row Level Security rifiuta un salvataggio, come in new row violates row-level security policy. Un assistente che si basa solo sul codice può ricorrere alle correzioni di quell'altro errore: spegnere Row Level Security, oppure aggiungere una regola using (true), che fa passare tutti. Nessuna delle due fa sparire questo errore. Tutte e due restano lì quando il grant finalmente arriva, e allora la porta è aperta su cassetti senza serratura.

Le parole del messaggio distinguono i due casi, anche se il numero non lo fa:

Il messaggio diceQuale serratura ha respintoCosa lo risolve
permission denied for tablela porta (il grant)un grant per il ruolo che il suggerimento nomina
new row violates row-level security policyle regoleuna policy che permetta quella riga
nessun errore, e la lista è vuotale regoleuna policy di lettura per quel ruolo

Cosa non risolve il 30 ottobre

Nessuna tabella che hai già. Ognuna conserva esattamente l'accesso che ha oggi, compresa una tabella che uno sconosciuto può leggere in questo momento.

Il cambiamento riguarda tabelle che non esistono ancora. Finora ogni nuova tabella arrivava con le porte aperte, quindi un'app costruita prima del 30 ottobre può averne una in cui nessuno ha mai montato le serrature: Row Level Security mai acceso, oppure acceso con una regola che fa entrare tutti. Il 30 ottobre lascia quelle stanze esattamente come sono.

Tre posti ti dicono a che punto sei:

  1. La pagina delle impostazioni Data API, a cui rimanda la mail. Nella dashboard si trova sotto Integrations, poi Data API, e mostra quali delle tue tabelle sono raggiungibili del tutto.
  2. Il Security Advisor, che secondo Supabase elenca le tabelle da rivedere prima del cambiamento.
  3. La vista da fuori. Nessuno dei primi due ti dice cosa riceve uno sconosciuto. Per quello chiedi alla tua app online come farebbe uno sconosciuto, ed è quello che fa la nostra scansione.

Come Reeve sorveglia le tabelle che aggiungi

Dopo il 30 ottobre, ogni tabella che il tuo builder aggiunge è una decisione nuova su chi passa dalla porta. Reeve controlla la risposta da fuori, e Monitor continua a controllarla.

  • La scansione gratuita chiede a ogni tabella che la tua app nomina quante righe riceverebbe un visitatore senza accesso, legge il conteggio e si ferma lì senza scaricare nessuna riga. Circa 20 secondi, senza account: scansiona la tua app.
  • Reeve Monitor ripassa tutti e nove i controlli ogni ora su un massimo di tre app e ti manda una mail il giorno in cui il tuo voto peggiora, così un deploy che ha aperto qualcosa non aspetta che sia tu ad andare a guardare.
  • Care ripassa gli stessi controlli e tiene una copia cifrata del tuo database Supabase fuori dal tuo account Supabase, così la correzione di un assistente che ricostruisce una tabella ha una copia a cui tornare. Come si fa la copia e come si rimette al suo posto.

Cosa include ogni piano è sulla pagina dei prezzi.

Cosa fare prima del 30 ottobre

Cosa fare

  • Lascia stare le tabelle che hai già se vuoi solo che la tua app continui a funzionare. Conservano i loro grant.
  • Chiedi al tuo builder di scrivere il grant, enable row level security e una policy nella stessa migrazione di ogni nuova tabella, come un'unica modifica.
  • Quando compare l'errore, leggi quale ruolo nomina il suggerimento. anon significa qualsiasi visitatore della tua app.
  • Non concedere nulla ad anon su una tabella finché Row Level Security non è acceso e non c'è una regola scritta. Le tabelle con persone o ordini di solito non hanno bisogno di alcun grant ad anon.
  • Rifiuta qualsiasi correzione che spegne Row Level Security o aggiunge using (true) per togliere un errore di permessi. Nessuna delle due lo tocca.
  • Controlla cosa può leggere uno sconosciuto dalle tabelle che hai già. Il 30 ottobre le lascia come sono.

Comincia dalla tabella che uno sconosciuto vorrebbe leggere di più, di solito quella con dentro delle persone, e scansiona la tua app per vedere cosa consegna oggi.

FAQ

La mia app Supabase smetterà di funzionare il 30 ottobre?

No. Ogni tabella che esiste il 30 ottobre conserva l'accesso che ha, e Supabase ha confermato che quei grant non verranno revocati. Cambia la prossima tabella creata dopo quella data. Nasce irraggiungibile dalla tua app finché qualcuno non le concede l'accesso, quindi la prima cosa a rompersi è la prima funzione nuova che ha bisogno di una tabella nuova.

Cosa significa "permission denied for table" in Supabase?

Significa che il tipo di visitatore che fa la richiesta non ha alcun accesso a quella tabella, quindi il tuo database l'ha rifiutata prima di guardare una sola riga. Arriva da Postgres, il database su cui gira Supabase, con il codice 42501, e di solito raggiunge la tua app come un 401 o un 403. Supabase aggiunge un suggerimento con l'istruzione GRANT esatta che farebbe entrare quel visitatore.

È sicuro eseguire il GRANT che suggerisce l'errore?

Solo quando la tabella ha già Row Level Security acceso e una regola scritta. Un grant ad anon permette a qualsiasi visitatore della tua app di chiedere righe alla tabella, perché la chiave che fa quelle richieste viaggia dentro la tua app. Con una regola al suo posto riceve le righe che la regola permette. Senza regola e con Row Level Security spento, le riceve tutte.

Questo cambiamento tocca Storage, l'accesso degli utenti o le mie edge function?

Storage e l'accesso degli utenti vivono in schemi propri, storage e auth, e Supabase dice che i loro grant e le loro impostazioni predefinite restano come sono. Le edge function sono un'altra storia. Una che usa la tua chiave segreta ha comunque bisogno di un grant su ogni tabella nuova, perché i grant automatici che spariscono coprivano service_role oltre ai due ruoli usati dai tuoi visitatori.

Posso riattivare il comportamento di prima?

Supabase documenta come farlo, con un'impostazione nella pagina Data API della dashboard oppure con SQL, e lo sconsiglia. Con quell'opzione attiva, ogni nuova tabella è raggiungibile da qualsiasi visitatore dal momento in cui esiste, e Row Level Security è l'unica cosa fra uno sconosciuto e le sue righe. È così che funzionavano tutti i progetti prima del cambiamento.

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.