Anatomia
de um
vazamento
Como os dados de clientes do Elegance Space e do Maya Massoterapia ficaram acessíveis sem nenhum login — passo a passo, e como fechar.
Ligue o RLS e veja a falha fechar
Este é o fluxo real de acesso. O RLS é o único elo que decide se o banco vaza — mexa no botão e acompanhe o banco trancar.
Três sites, um banco só
Os três projetos compartilham o mesmo backend Supabase e a mesma chave pública. Expor um expõe a superfície de todos.
Elegance Space
Agendamento de unhas.
Maya
Agendamento e pacotes.
LV Solutions
Painel administrativo.
O LV Solutions prova que dá para fazer certo no mesmo banco — a diferença está numa única linha. Esta apresentação mostra o que faltou nos outros dois.
A chave é pública de propósito
Todo app Supabase embarca uma chave anon no JavaScript que o navegador baixa. Isso é normal — ela nasceu para ser pública.
O que impede essa chave de ler o banco inteiro é o RLS: uma trava, por tabela, que diz “quem pode ver qual linha”. Sem RLS, a chave pública abre tudo.
O login é uma fachada
A página de login é desenhada pelo próprio navegador (é um app JavaScript). Nenhum dado real mora nela — ela só conversa com o backend. Traduzindo: o atacante nem tenta o login. Ele mira o backend direto.
Tentar “adivinhar a senha” seria o caminho errado — e o mais difícil. O caminho fácil é outro.
Descobrir que é Supabase
Basta olhar o código que o site entrega. O próprio navegador mostra as conexões para *.supabase.co. Confirmado o alvo: um banco Supabase por trás do site.
Pegar a URL e a chave no bundle
Elas ficam dentro do JavaScript que o site entrega a todo visitante. Abrir F12 → Network, achar o index-….js e procurar por supabase.co e sb_publishable_.
Descobrir os nomes das tabelas
Também estão no mesmo JavaScript, nas chamadas .from("tabela"). Foi assim que apareceram todas:
professionals · services
weekly_schedule · schedule_blocks
maya_client_packages · maya_services
maya_package_sessions · +5
Falar direto com o banco, pulando o login
O Supabase expõe cada tabela numa URL. Basta enviar a chave pública no cabeçalho — sem usuário, sem senha, sem login.
Aberto vs fechado
A resposta do banco conta tudo. É literalmente a diferença entre um site vulnerável e um site seguro — no mesmo servidor.
Um único elo falhou
Nenhum dos passos 1 a 4 é “falha” — a chave é pública mesmo. O que abriu tudo foi a camada final.
Com o RLS ligado, o Passo 5 já devolve 401. Os passos 1–4 continuam possíveis — e não levam a lugar nenhum.
O que estava ao alcance de qualquer um
Uma linha por tabela estanca na hora
Ligar o RLS. Sem política, o banco passa a negar tudo por padrão — o vazamento fecha imediatamente. Depois você reabre só o mínimo público, com calma.
- ✓Ligar RLS nas 16 tabelas — fecha o Passo 5 na hora.
- ✓Reabrir só o público (serviços, horários) por política — nunca appointments/clients.
- ✓Verificar: repetir o Passo 5 → tem que virar 401. O script checar_vazamento.py testa as 16 de uma vez.