← Guias
5 min de leitura

A chave service_role do Supabase no navegador: o erro mais grave de todos

A service_role ignora a RLS e dá acesso total ao banco. Se ela foi para o front-end, qualquer visitante pode ler e apagar tudo. Veja como achar e o que fazer.

O Supabase tem dois tipos de chave. A pública (anon, ou sb_publishable_…) respeita a RLS e pode ir para o site. A secreta (service_role, ou sb_secret_…) passa por cima de todas as regras: ela lê, altera e apaga qualquer linha de qualquer tabela.

É por isso que ela é tão tentadora quando aparece um erro de permissão: troca a chave, o erro some. E o banco inteiro fica acessível para qualquer pessoa que abrir o site.

Como ela vai parar no navegador

  • Escrita direto num arquivo que o front importa (lib/supabase.ts, por exemplo).
  • Guardada numa variável com prefixo público: NEXT_PUBLIC_…, VITE_…, EXPO_PUBLIC_…. Esses prefixos existem justamente para mandar o valor ao navegador.
  • Usada num componente com "use client".

Como procurar

  1. 1No código, procure por service_role, SERVICE_ROLE e sb_secret_.
  2. 2A chave antiga é um JWT (começa com eyJ). Cole o trecho do meio num decodificador de JWT: se aparecer "role": "service_role", é ela.
  3. 3No site publicado, abra as ferramentas do navegador (F12) → Sources, e busque por service_role nos arquivos carregados.

O que fazer, nesta ordem

  1. 1Troque a chave já: no painel do Supabase, em Settings → API Keys, gere uma chave secreta nova e desative a antiga. Enquanto a antiga valer, o vazamento continua.
  2. 2Tire a chave do front. O que precisava dela vira uma rota no servidor ou uma Edge Function, que confere o login antes de agir.
  3. 3Ligue a RLS nas tabelas e use a chave pública no site.
  4. 4Olhe os logs do banco em busca de leituras ou exclusões que você não fez.

Apagar a chave do código não basta: ela já foi baixada por todo mundo que abriu o site e pode estar no histórico do Git. Só a troca da chave encerra o problema.

Dicas curtas de segurança para quem cria com IA: siga @npx_vibedefender no Instagram.