Início / RLS / Mudança de grants de 30/10 · Read in English

Supabase RLS · Mudança na plataforma

Mudança de grants do Supabase em 30/10: o que quebra e a correção que vaza

Supabase · outubro de 2026✓ código testado num banco de verdade
TL;DR

A partir de 30/10, uma tabela nova em public fica inacessível pra anon / authenticated até você dar GRANT. Tabelas que já existem continuam funcionando. Coloque grant + RLS + policies na mesma migration. Não resolva o 42501 com grant ... on all tables: isso libera também toda tabela que está com RLS desligado.

01 O que muda em 30 de outubro

Até agora, toda tabela criada em public recebia automaticamente privilégios completos (select / insert / update / delete e outros) pra anon, authenticated e service_role, via default privileges. Em 30 de outubro de 2026 o Supabase desliga isso em todos os projetos existentes (projetos novos já vêm assim desde um rollout gradual que começou em 30 de maio). A partir daí:

Tabelas novas

Criadas sem GRANT, ficam invisíveis pra Data API (supabase-js, PostgREST, GraphQL), não importa como foram criadas: SQL editor, migration, CLI, MCP ou ferramenta de IA.

Tabelas existentes

Não mudam. Continuam com os grants que têm hoje, então o app que está no ar segue funcionando.

RLS e policies

Iguais. O grant decide se um role pode tocar na tabela; o RLS decide quais linhas.

Conexões diretas ao Postgres (psql, ORM, servidor com connection string) não são afetadas. Fonte: anúncio oficial do Supabase (em inglês).

02 Como é o "quebrou"

A primeira tabela nova depois da virada devolve isso pela API, em vez das linhas:

resposta (exemplo do anúncio do Supabase)

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

O Postgres recusa a query antes mesmo de o RLS rodar. É o novo padrão funcionando como deveria, não um bug nas suas policies.

03 A correção que vaza

O jeito mais rápido de sumir com o erro é o grant em massa da seção de rollback do anúncio:

não cole isso como correção

grant select, insert, update, delete on all tables in schema public
  to anon, authenticated, service_role;

Funciona, e também libera todas as tabelas de public, inclusive as que você nunca quis expor. Qualquer uma delas com RLS desligado passa a poder ser lida e escrita por quem tiver sua anon key, que vai junto no seu frontend. O novo padrão era a chance de parar de expor tabela sem querer; o grant em massa devolve o problema. Peça pra uma ferramenta de IA "corrigir o erro de permissão" e essa linha é uma resposta bem provável.

Dê grant por tabela, e só o que cada role precisa.

04 O padrão de migration que funciona

Trate grant, RLS e policies como uma coisa só, na mesma migration, pra tabela nunca existir pela metade:

migration.sql

create table public.invoices (
  id         bigint generated always as identity primary key,
  user_id    uuid not null references auth.users(id),
  amount     numeric not null
);

alter table public.invoices enable row level security;

create policy "owner reads" on public.invoices for select to authenticated
  using (user_id = (select auth.uid()));

-- só o role e as operações que o app realmente usa
grant select on public.invoices to authenticated;

Sem grant pra anon aqui, porque visitante deslogado não lê fatura. Se a tabela usa serial / bigserial em vez de identity e a API insere nela, a sequence precisa do próprio grant: grant usage, select on sequence public.invoices_id_seq to authenticated;

05 Veja o que os roles da API alcançam hoje

Rode isso no SQL editor. Lista toda tabela e view de public, se anon ou authenticated conseguem ler, e se o RLS está ligado:

check.sql

select c.relname,
       has_any_column_privilege('anon', c.oid, 'select')          as anon_can_read,
       has_any_column_privilege('authenticated', c.oid, 'select') as auth_can_read,
       c.relrowsecurity                                              as rls_on
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind in ('r', 'p', 'v', 'm')
order by 1;

Tabela com anon_can_read = true e rls_on = false pode ser lida por qualquer um com a sua anon key. Dois detalhes deixam essa consulta mais rigorosa que a versão comum baseada em information_schema.table_privileges:

Grants de coluna

grant select (id, email) on profiles to anon não aparece como privilégio de tabela, mas a API continua servindo essas colunas. has_any_column_privilege pega grant de tabela e de coluna.

Views

Views também aparecem na API e, por padrão, leem as tabelas como o dono da view, pulando o RLS. Crie views com security_invoker = on pra elas respeitarem o RLS de quem chama.

06 Pra não voltar a acontecer

O novo padrão só te protege enquanto toda migration estiver certa. Dois checks grátis ajudam:

No CI

npx airlock-migrate lê seus arquivos de migration e quebra o build quando um deles cria tabela sem ligar o RLS, ou desliga o RLS. São justamente as tabelas que um grant em massa exporia. Também avisa sobre view sem security_invoker = on. Ele não aponta os grants em si, e só enxerga tabelas que passam pelos seus arquivos de migration.

No banco em produção

SUPABASE_DB_URL=... npx airlock-rls confere o banco rodando atrás de tabelas com RLS desligado e policies que deixam todo mundo passar. Configure no CI (em inglês).

◆ GRÁTIS · MIT · npm + GitHub Action

Pegue isso antes de ir pro ar

airlock-rls é um gate de CI que quebra o build quando uma tabela vai pro ar exposta ou uma policy é permissiva: o mesmo tipo de bug, pego no CI contra um banco com as suas migrations aplicadas, antes de chegar em produção.

npx airlock-rls→

Ou comece pelo nextjs-supabase-starter: auth + uma tabela com RLS + um teste de isolamento, pra começar de um padrão que já vem selado.

PDF GRÁTIS

Baixe o cheat sheet de RLS do Supabase

As regras de ouro, as armadilhas que vazam em produção, policies corretas e o teste de isolamento, numa página só (em inglês).

FAQ

Minhas tabelas atuais param de funcionar em 30 de outubro?

Não. O Supabase só muda o padrão das tabelas criadas depois da virada. As tabelas que já existem mantêm os grants atuais. O primeiro a quebrar é a próxima tabela nova criada sem GRANT.

Essa mudança deixa meu app mais seguro sozinha?

Só pras tabelas novas. Toda tabela existente mantém os grants antigos, então uma que está com RLS desligado hoje continua legível pela API depois de 30/10. Rode o check acima e ligue o RLS em tudo que aparecer com anon_can_read true e rls_on false.

Dou grant pra anon ou pra authenticated?

Pro role que realmente precisa da tabela. Dado que só usuário logado vê recebe grant pra authenticated e nenhum pra anon. Dado público, como um catálogo de produtos, pode ter grant pra anon com uma policy de RLS que permita a leitura.

O service_role também é afetado?

Sim. Ele também perde os grants automáticos em tabelas novas, então um backend usando a chave service_role recebe 42501 numa tabela nova até você dar o grant. Depois do grant, ele continua ignorando o RLS.