Seu app do Supabase é seguro?
O Supabase pode guardar dados reais de usuários? Pode, e foi feito para ser consultado do navegador. É justamente por isso que duas configurações decidem tudo.

Os logotipos são propriedade de seus respectivos donos e são exibidos apenas para indicar compatibilidade.
Em resumo
- O Supabase pode guardar dados reais de usuários, e foi feito para ser consultado direto de um navegador. É justamente por isso que as regras das suas tabelas fazem todo o trabalho.
- A chave publicável pertence ao seu app. sb_secret_… e service_role ignoram todas as regras que você escreveu.
- Tabelas feitas no Table Editor ganham Row Level Security automaticamente. Tabelas criadas rodando SQL não.
O Supabase te dá um banco Postgres de verdade com uma API já na frente dele, e é por isso que um app consegue estar conversando com dados reais vinte minutos depois de você começar. O que surpreende as pessoas mais tarde é que essa mesma API é alcançável por qualquer um, de qualquer lugar, com credenciais impressas dentro do seu app.
Aqui está o que guia após guia erra: isso não é defeito, e esconder não é a correção. O Supabase foi projetado para ser consultado direto de um navegador. A proteção sempre foi para morar em outro lugar, e saber onde é quase tudo o que há para saber sobre tocar um app com Supabase em paz.
Por que o seu banco de dados está na internet de propósito
Porque o seu app fala com ele a partir do navegador do seu visitante, e não de um servidor que você mantém.
Pense numa loja. O seu app é a vitrine, entregue inteira a cada visitante. O seu banco de dados é o estoque, e no Supabase o estoque tem, de propósito, uma porta própria para a rua, para a sua vitrine se abastecer sem um serviço de entrega no meio. É essa porta que te poupa de escrever um backend.
O que significa que a porta é pública, e o endereço dela está no seu app porque o seu app precisa bater nela. Não existe arranjo em que esse endereço seja secreto. Então a pergunta nunca foi "estranhos conseguem chegar ao meu banco?". Conseguem, por projeto. A pergunta é o que ele entrega quando eles pedem.
A chave do Supabase no meu app deveria estar ali?
Uma delas sim. A outra nunca, e elas parecem quase idênticas.
A chave publicável (sb_publishable_… nos projetos novos, anon nos
antigos) diz a qual projeto um pedido pertence. Ela não carrega privilégio
nenhum próprio, e é por isso que a própria documentação do Supabase a descreve
como segura para empacotar em páginas web e apps de celular. Encontrá-la no seu
app não é um achado.
A chave secreta, sb_secret_… ou a antiga service_role, é o oposto. Ela
ignora as suas regras por completo e lê e escreve em toda linha de toda tabela,
de qualquer lugar. O lugar dela é um servidor, uma edge function, um worker:
nenhum lugar que um navegador alcance.
As duas ficam lado a lado na mesma página do painel e têm o mesmo formato. Se alguma já foi colada em código de frontend, troque a chave no painel antes de editar qualquer coisa, porque apagar a linha não fecha a porta.
Essa página é Settings e depois API Keys, e ela guarda quatro valores em vez de dois.
A configuração que decide o que a porta entrega
Row Level Security: uma chave por tabela que decide, linha a linha, quem pode ler o quê. É todo o motivo pelo qual uma chave publicável é segura.
Com ela desligada, essa chave devolve a tabela inteira a qualquer um que peça. Com ela ligada e uma política escrita, o próprio banco filtra cada pedido, inclusive pedidos que nunca passaram pelo seu app.
Dois detalhes decidem se você realmente tem isso, e nenhum é visível de dentro do seu app:
Como a tabela foi criada. O Supabase liga o Row Level Security automaticamente nas tabelas feitas no Table Editor do painel. Tabelas criadas rodando SQL não ganham isso e precisam ser ligadas de propósito. Arquivos de migração, scripts e esquemas gerados por IA criam tabelas todos rodando SQL, então um projeto feito assim pode ter uma fileira de tabelas desprotegidas que parecem exatamente iguais às protegidas.
O que a política diz. Ligado quer dizer fechado até uma política abrir. Uma política que permite todo mundo abre de vez enquanto o painel continua informando que a tabela está com Row Level Security ligado, o estado que parece protegido e não está.
O armazenamento é separado de novo. Um bucket público é listável e baixável por qualquer um com o endereço do seu projeto, digam o que disserem as regras das suas tabelas.
Como conferir o seu próprio projeto do Supabase em uns dez minutos
Authentication → Policies. Leia a lista inteira. Qualquer tabela mostrando Row Level Security como desligado pode ser lida por qualquer um. Nas que mostram ligado, abra a política e leia o que ela de fato permite.
Settings → API. Confirme que a chave que o seu app entrega é a publicável. Se
uma chave secreta já esteve em código de frontend, troque a chave aqui primeiro.
Se o seu painel mostra chaves que começam com sb_publishable_ e sb_secret_
em vez de anon e service_role, esse é
o formato mais novo, e a mesma regra decide qual
das duas fica no seu app.
Storage → Buckets. Veja quais estão públicos e se era isso mesmo que você queria para os arquivos dentro deles.
E então olhe de fora. Tudo acima é o que o seu painel diz que está configurado. O que um pedido anônimo realmente recebe de volta é outra pergunta, e é a que o nosso scan gratuito responde: ele consulta do jeito que um estranho consultaria, sem ler nenhuma das suas linhas, e te dá uma nota em uns 20 segundos: veja o que o seu app expõe.
O que fazer
- A sua API do Supabase é pública de propósito. A proteção são as regras nas suas tabelas, nunca o sigilo do endereço.
- A chave publicável pertence ao seu app.
sb_secret_…eservice_rolenunca, e uma vazada ignora todas as regras que você escreveu. - Tabelas feitas no Table Editor ganham Row Level Security automaticamente. Tabelas criadas rodando SQL não.
- Ligado não é restrito. Leia a política, não só a chave.
- Buckets de armazenamento têm configurações próprias, então tabelas trancadas não dizem nada sobre os seus arquivos.
Abra Authentication → Policies e leia a lista uma vez de cima a baixo. As tabelas marcadas como desligado são por onde começar, e se você preferir percorrer toda a superfície em forma de lista, o checklist de segurança de 10 minutos é a versão curta. Ache o que achar, saber que você consegue colocar os dados de volta importa tanto quanto trancá-los, e isso depende inteiramente de o que você está copiando.
Se você prefere que isso não dependa de lembrar, veja como funcionam os backups automáticos do Supabase.
O que pode dar errado de verdade com o Supabase
Nada disso significa que você fez algo errado: são as brechas habituais quando se está indo rápido. Aqui está o que vale a conferida:
Row Level Security (RLS) desligada
O RLS é a regra do Supabase sobre quem pode ler ou alterar cada linha de uma tabela. Com a chave pública “anon” (que deve estar no seu app), qualquer um pode consultar seu banco de dados diretamente. O RLS é o que o impede de ver linhas que não são dele. Se estiver desligada, uma tabela pode ser totalmente legível, ou até editável, por qualquer um. É a configuração mais importante do Supabase, e o Reeve a verifica contando linhas, nunca lendo-as.
Uma chave service_role vazada
O Supabase te dá duas chaves. A chave “anon” é pública por design e segura no navegador. A chave “service_role” ignora todas as suas regras de segurança e deve viver apenas em um servidor. Se ela algum dia acabar no código do front-end do seu app, alguém pode fazer qualquer coisa com seus dados. O Reeve decodifica as chaves que encontra e diz exatamente qual está exposta: a “anon” segura recebe um tique verde, a “service_role” é um alerta vermelho.
Buckets de armazenamento públicos
Os arquivos que as pessoas enviam vivem em “buckets” do Supabase Storage. Um bucket definido como público significa que qualquer um pode listar e baixar o que há dentro, então envios privados podem se tornar visíveis para todos. O Reeve verifica se os seus buckets são listáveis; ele nunca baixa os arquivos de ninguém.
Sua API aberta a qualquer site (CORS)
O Supabase dá ao seu banco de dados um endereço web (via PostgREST). Combinado com uma configuração de compartilhamento permissiva demais, outro site poderia chamar seus dados a partir do navegador de um visitante. O Reeve verifica se os seus endpoints respondem a estranhos e a outros sites, sem nunca usá-los para mudar nada.
Tabelas e endpoints expostos sem regras
Cada tabela que você cria é acessível pela API do Supabase; isso é por design, e o RLS deve protegê-la. Mas uma tabela nova adicionada com pressa, antes de suas regras serem definidas, pode ficar brevemente (ou de forma duradoura) aberta. O Reeve verifica o que está de fato acessível por fora.
Chaves ou configuração deixadas no app implantado
Além das próprias chaves do Supabase, os apps muitas vezes carregam outras configurações e segredos no código front-end ou em um .env exposto. O Reeve lê o código carregado do seu app e verifica se há arquivos de configuração acessíveis, depois diz quais valores são seguros de tornar públicos e quais não são.
O que o Reeve é, e o que não é
O Reeve é uma verificação gratuita, somente leitura e por fora, como um inspetor que testa as portas sem entrar. É rápida e pega os erros comuns de grande impacto. Não é uma auditoria de segurança completa, e uma nota limpa não é garantia. Significa que as portas óbvias estão fechadas. Tudo o que o Reeve faz é passivo: ele conta linhas em vez de lê-las, e nunca baixa seus arquivos.
O Supabase te dá ferramentas de segurança reais (um Security Advisor e um linter de banco de dados que sinalizam problemas de RLS e de exposição bem no painel), e vale muito a pena usá-los. O que o Reeve acrescenta: a maioria de quem constrói no Supabase vive no seu criador de apps, não no editor SQL, e o advisor fala em linguagem de desenvolvedor. O Reeve verifica o seu app inteiro por fora, do jeito que um invasor chegaria aos seus dados, e explica o que encontra em palavras simples. E se você preferir não monitorar você mesmo, nós podemos.
Quer que seja resolvido, não só verificado?
O Reeve Care continua monitorando seu app, faz backup dos seus dados e ajuda você a corrigir as coisas quando quebram, para que você siga criando em vez de se preocupar.
Conheça o Reeve CarePerguntas frequentes
O que é o RLS do Supabase e eu realmente preciso dele?
O RLS (Row Level Security) decide quem pode ver ou alterar cada linha das suas tabelas. Como o seu app envia uma chave pública “anon” capaz de consultar o banco de dados diretamente, o RLS é o que impede que os dados de um usuário fiquem visíveis para todos. Sim: para qualquer tabela com dados reais, você precisa dele ligado. O Reeve verifica se está, sem ler seus dados.
A chave anon do Supabase é segura de expor?
Sim. A chave “anon” foi feita para viver no seu front-end, e sozinha ela só faz o que suas regras de RLS permitem. A chave que nunca deve ser exposta é a “service_role”, que ignora todas as regras. O Reeve decodifica as chaves do seu app e diz qual é qual.
O que acontece se a minha chave service_role vazar?
A chave service_role ignora todas as regras de segurança, então quem a tiver pode ler, alterar ou apagar todos os seus dados. Se ela está no seu código front-end, trate-a como comprometida: rotacione-a no painel do Supabase e mova-a para um servidor. O Reeve sinaliza uma chave service_role exposta como um problema crítico.
O Reeve pode verificar meu Supabase sem a senha do meu banco de dados?
Sim. O Reeve só usa o que o seu app já expõe publicamente: a mesma chave anon e os mesmos endpoints que o navegador de qualquer visitante usa. Ele nunca precisa da senha do seu banco de dados, nunca faz login como administrador e nunca lê nem baixa suas linhas ou arquivos.
Por que o Supabase deixa um navegador falar com o meu banco de dados?
Porque esse é o produto. O Supabase coloca uma API na frente do Postgres para o seu app consultar dados sem que você escreva e hospede um backend, e é isso que torna a construção tão rápida. A segurança não vem de esconder essa API, que não dá para esconder. Vem do Postgres se recusando a devolver linhas a que o visitante não tem direito.
Ligar o Row Level Security numa tabela a torna privada?
Torna a tabela fechada até você escrever uma política, o que é o ponto de partida seguro. Mas uma política que permite todo mundo reabre a tabela enquanto o painel continua mostrando o Row Level Security como ligado. Ligado e restrito são dois estados diferentes, e só um deles se vê de relance.
Quais tabelas têm mais chance de estar desprotegidas?
As criadas rodando SQL em vez de clicando no Table Editor: arquivos de migração, scripts e esquemas escritos para você por um builder de IA. O Table Editor liga o Row Level Security automaticamente. O SQL não, e depois nada aponta a diferença.
O meu armazenamento no Supabase é coberto pelo Row Level Security?
O armazenamento tem configurações próprias e separadas, então um banco bem trancado não diz nada sobre os seus arquivos. Um bucket marcado como público pode ser listado e baixado por qualquer um que saiba o endereço do seu projeto, com ou sem link do seu app para o que há dentro.