Noções de segurança
Chave de API exposta no frontend: o que 30.998 apps entregam
Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.

Em resumo
- Uma chave de API exposta no seu frontend é quase sempre do tipo inofensivo. Encontramos uma chave digna de nota em 1.332 de 30.998 apps, e 1.080 delas só carregavam uma chave de API do Google.
- A chave service_role do Supabase, contra a qual todo tutorial avisa, apareceu em 3 apps de 30.998. Uma chave secreta do Stripe também apareceu em 3.
- Chaves que gastam dinheiro ou leem dados pela própria forma apareceram em 54 apps. Uma tabela aberta do Supabase apareceu em 2.096.
Alguém abre seu app, aperta F12 e diz que existe uma chave de API exposta no seu frontend. A palavra usada costuma ser "vazou". Raramente dizem qual chave é, e os conselhos que você encontra depois tratam todas como a mesma emergência.
Não são a mesma emergência, e agora conseguimos colocar números nessa distância. Entre 12 e 14 de agosto de 2026 rodamos nove verificações externas em 30.998 apps no ar criados com Lovable, Bolt, v0, Replit e Base44, e lemos o JavaScript que cada um entrega a um navegador. Foi isto que havia dentro.
Uma chave de API exposta no frontend é mesmo um problema?
Quase nunca, e o formato desse "quase nunca" é mais desequilibrado do que esperávamos.
Encontramos uma chave digna de nota em 1.332 dos 30.998 apps. Em 1.080 deles, a única coisa que achamos foi uma chave de API do Google, que é exatamente a credencial que deve estar na sua página. O que protege essa é uma configuração guardada do lado do Google, e escondê-la nunca fez parte do combinado.
Os outros 29.666 apps não entregavam nada que nossa verificação de segredos trate
como problema. Esse número precisa de uma ressalva para ser honesto: as chaves
publicáveis ficam de fora. Uma chave anon do Supabase ou uma chave pk_ do
Stripe pertence ao navegador, então a marcamos como algo que você fez certo e ela
nunca entra nessas contagens.
O que contamos e o que não conseguimos contar
Carregamos cada app do jeito que um visitante carrega, num navegador de verdade, e lemos o JavaScript baixado. Tudo o que vem a seguir é uma forma encontrada nesse código.
Reconhecemos os formatos de chave que conhecemos. Stripe, OpenAI, Anthropic, AWS, Google e Supabase têm prefixos identificáveis, e um JWT do Supabase declara o próprio papel em texto legível na seção do meio. Uma credencial num formato que não reconhecemos não está nestes números, então leia-os como um piso.
Não usamos nenhuma chave que encontramos. Nenhuma vez, em nenhum app.
Registramos o tipo e uma dica mascarada no formato sk_live_…a1b2, e o valor
real não foi escrito em lugar nenhum.
Nenhum app é nomeado. Nem aqui, nem no conjunto de dados, nem em nada que publicamos.
Quase todos são apps publicados no domínio do próprio builder. O método completo, a amostra e cada número por trás deste artigo estão no nosso relatório de varredura, incluindo o que não conseguimos medir.
O que os 30.998 apps entregavam de verdade
Uma tabela, ordenada pela frequência com que vimos cada coisa. A verificação de segredos foi concluída em todos os 30.998 apps, então cada contagem abaixo é sobre todos eles.
| O que encontramos no código do navegador | Apps |
|---|---|
| Chave de API do Google | 1.142 |
| Um valor de alta entropia ao lado de um nome "secret" ou "password" | 204 |
| Chave da OpenAI | 33 |
| Chave de acesso da AWS | 9 |
| Chave da Anthropic | 5 |
Chave service_role do Supabase | 3 |
| Chave secreta do Stripe | 3 |
| Chave restrita do Stripe | 2 |
As linhas somam mais de 1.332 porque um app pode carregar duas delas. Separe esses mesmos 1.332 apps em grupos que não se sobrepõem e o quadro fica ainda mais nítido: 1.080 tinham uma chave do Google e nada mais, 198 tinham um valor de alta entropia que pode ou não ser uma credencial real, e 54 tinham uma chave que é um segredo genuíno pela própria forma.
O segundo grupo merece ser descrito com cuidado. Um valor de alta entropia ao
lado de uma palavra como secret ou password pode ser uma credencial viva, ou
pode ser um identificador de sessão, um hash de build ou um token público com um
nome infeliz. Sinalizamos como algo que vale olhar, e de fora ninguém consegue
dizer qual desses é.
Os 54 do terceiro grupo são a coisa real. Todos menos dois saíram com nota D ou F, porque um único achado crítico limita a nota a D por melhor que o app tenha feito o resto. O maior grupo isolado dentro deles é a chave da OpenAI, com 33, e essa não tem nenhuma configuração que a torne segura num navegador.
A chave contra a qual todos avisam foi a coisa mais rara que encontramos
Três apps. Foi essa a quantidade que entregava uma chave service_role do
Supabase, a que passa por cima de cada regra de tabela que você escreveu. Uma
chave secreta do Stripe também apareceu três vezes.
Coloque isso ao lado da outra metade da mesma varredura. Dos apps que escaneamos,
8.429 nomeavam um projeto Supabase, e os dois achados ficam dentro desse mesmo
grupo. Três deles entregavam a chave service_role. Em 2.096 deles, ao menos uma
tabela respondeu a uma requisição sem login nenhum, e em 394 essa tabela tinha
nome de pessoas: users, profiles, customers, orders.
Os 2.096 são um piso. 4.749 dos 8.429 nunca responderam à nossa verificação de
banco de dados, por motivos que não vemos de fora, e esses ficam registrados como
desconhecidos em vez de limpos. As três chaves service_role são uma contagem
exata, porque uma chave é lida de um código que todo app entrega.
Por que os avisos apontam para a chave errada
Só vemos o lado de fora desses apps, então não podemos dizer por quê. O que conseguimos mostrar é qual erro sobrevive.
Copiar a chave errada do Supabase é genuinamente fácil. Num projeto antigo anon
e service_role ficam lado a lado no mesmo painel do dashboard, têm o mesmo
comprimento e o mesmo formato, e
nada quebra se você pegar a errada.
Ainda assim aconteceu só três vezes em 30.998 apps, porque nada empurra você para
lá. Colar qualquer uma das duas faz o app funcionar.
A tabela aberta tem uma força por trás. O Row Level Security é ligado, o app para de mostrar dados, uma policy que permite todo mundo é escrita para voltar a funcionar, e a partir desse momento o dashboard informa a tabela como protegida. Ligá-lo não é o mesmo que estar protegido. Nosso scan classifica essa tabela como achado crítico num dia em que seu dashboard está mostrando a chave ligada e uma policy no lugar.
Como encontrar de graça uma chave de API exposta no seu app
Comece na mão, porque custa cinco minutos e não exige instalar nada. Abra seu
site no ar, veja o código-fonte da página e procure por quatro sequências: AIza
para uma chave do Google, sk_ para um segredo do Stripe ou de provedor de
modelo, service_role para a chave do Supabase que ignora suas regras, e eyJ
para qualquer token do Supabase. Tudo o que voltar já está nas mãos de cada
visitante que você tem.
Isso cobre a página em si. O que escapa é o JavaScript que a página carrega
depois, e é justamente por isso que nosso próprio scanner abre um app num
navegador de verdade e lê os bundles em vez do HTML. Procurar na mão também não
diz se o token eyJ que você achou é a chave anon ou a secreta, porque as duas
têm o mesmo comprimento e o mesmo formato.
Nosso scan gratuito cobre as duas coisas. Ele carrega seu app num navegador de verdade, lê o código que chega de fato, decodifica cada token do Supabase e informa o papel escrito dentro dele, de modo que uma chave publicável volta marcada como correta em vez de enterrada num muro de vermelho. Você recebe uma nota, uma pontuação e as contagens na tela em cerca de 20 segundos, sem conta. Dê um endereço de e-mail e você recebe também a lista detalhada, com uma correção escrita para o seu builder que dá para colar direto.
Três coisas que ele não faz, e são as razões de ser seguro rodar num app no ar:
nunca faz login, nunca escreve nada e nunca guarda uma chave que encontra. Um
segredo exposto é guardado como uma dica mascarada do tipo sk_live_…a1b2, e o
valor real é descartado. Escaneie seu app, ou leia antes
o que cada uma das nove verificações olha.
O que fazer, na ordem que os números sugerem
O que fazer
- Identifique a chave antes de reagir a ela. O prefixo resolve para o Stripe e para as chaves novas do Supabase; numa chave antiga do Supabase, quem decide é o campo
roledentro do token. - Se for uma chave do Google, restrinja em vez de esconder. Restrição de Sites, seu domínio, só as APIs que você usa, mais um teto de cota diária. De graça, uns cinco minutos, sem mudar código.
- Se for uma chave secreta de verdade, rotacione primeiro. Apagá-la do código não fecha nada, porque o valor antigo continua no seu histórico de versões e nas cópias em cache do seu site.
- Depois vá ler as regras das suas tabelas, que é onde os números colocam a exposição real. Comece pelas tabelas que guardam pessoas.
- Confira cobrança e registros depois de qualquer exposição de chave secreta. Rotacionar interrompe o que vem a seguir, e não diz nada sobre o que já aconteceu.
Percorra a lista inteira de uma vez com a checklist de segurança de 10 minutos, que cobre a chave e as regras de tabela junto com as outras coisas que vale fechar num app recém-lançado. E se a metade de banco de dados deste artigo é a que preocupa você, ela tem um levantamento próprio: quem consegue ler seu banco de dados Supabase.
Perguntas frequentes
Como sei se minha chave de API vazou?
Abra seu site no ar, veja o código-fonte da página e procure pelas formas: AIza para uma chave do Google, sk_ para um segredo do Stripe ou de provedor de modelo, e eyJ para um JWT do Supabase. Tudo que aparecer já está nas mãos de cada visitante. Nosso scan gratuito faz essa mesma leitura de fora e informa o que consegue ver em cerca de 20 segundos, sem conta para receber a nota.
Uma chave de API escrita direto no código é sempre um problema de segurança?
Não, e acreditar nisso é justamente o que ensina as pessoas a ignorar o aviso. Algumas chaves são publicadas de propósito: uma chave anon do Supabase, uma chave pk_ do Stripe e uma chave de configuração web do Firebase foram todas feitas para morar no navegador, e o que protege seus dados são as regras por trás delas. Uma chave secreta é o caso oposto e o lugar dela é um servidor. O prefixo diz qual das duas você tem na frente.
Disseram que minha chave do Supabase está exposta. É a ruim?
Quase certamente não. As duas chaves do Supabase se parecem, então leia o papel dentro do token ou confira o prefixo: anon e sb_publishable_ devem ser públicas, service_role e sb_secret_ não. Encontramos uma chave service_role em 3 apps de 30.998, então as chances pesam muito para a inofensiva. Se for mesmo a secreta, rotacione hoje no painel do Supabase.
Com o que eu deveria me preocupar no lugar?
Com as regras nas tabelas do seu banco. Dos apps em que conseguimos concluir essa verificação, mais da metade tinha ao menos uma tabela que respondia a uma requisição sem login nenhum, e em 394 deles a tabela aberta tinha nome de pessoas: users, profiles, customers, orders. Isso é muito mais comum do que qualquer chave vazada e muito mais silencioso, porque o app funciona exatamente igual nos dois casos.
Tirei a chave do meu código. Está fechado agora?
Não sozinho. O valor antigo continua existindo no seu histórico de versões e em qualquer cópia em cache da página, então quem já o recolheu pode seguir usando. O que realmente fecha a porta é rotacionar a chave no painel do provedor, e esse é o primeiro passo, não o último. Depois disso, confira a cobrança e os registros por uso que você não consiga explicar.