Chaves secretas no seu frontend: encontre e corrija hoje
Apps construídos com IA costumam levar chaves de API no JavaScript. Quais podem ficar expostas, como achar as que não podem e em que ordem corrigir.
Nesta página · 4 seções
Principais pontos
- Tudo que está no frontend do seu app é público, incluindo cada chave de API empacotada no JavaScript. Uma empresa de segurança encontrou mais de 400 secrets expostos ao analisar 5.600 apps construídos com IA.
- Algumas chaves foram feitas para ser públicas (a publishable do Supabase, a publishable do Stripe). Outras nunca podem chegar ao navegador (a secret do Supabase, a secret do Stripe, OpenAI e outras APIs pagas).
- Se uma chave secreta já esteve no seu frontend, rotacione-a primeiro e depois mova para o servidor a chamada que ela alimenta.
Todo construtor de apps com IA faz a mesma troca: o jeito mais rápido de fazer uma funcionalidade funcionar é chamar o serviço direto do navegador. Funciona, e também coloca a chave desse serviço no JavaScript que todo visitante baixa. Qualquer pessoa que abra as ferramentas de desenvolvedor do navegador pode copiá-la.
Este post mostra quais chaves podem ficar expostas, como encontrar as que não podem e o que fazer quando você encontrar uma. Ele faz parte do guia para deixar um protótipo construído com IA pronto para usuários reais; para as regras de acesso ao banco de dados, veja Supabase RLS: seu app construído com IA está vazando dados?
Quão comuns são as chaves vazadas em apps construídos com IA?
Muito. A Escape, uma empresa de segurança, analisou 5.600 apps construídos com ferramentas de programação com IA e reportou mais de 2.000 vulnerabilidades altamente críticas, mais de 400 secrets expostos e 175 casos de dados pessoais expostos, incluindo dados de contas bancárias (Escape).
A causa é estrutural. As ferramentas de build embutem no JavaScript, no momento do build, as variáveis de ambiente que têm um prefixo público. A documentação do Vite avisa que variáveis VITE_ “não devem conter informações sensíveis, como chaves de API”, porque “os valores dessas variáveis são empacotados no seu código-fonte no momento do build” (Vite). O Next.js faz o mesmo com o prefixo NEXT_PUBLIC_ (Next.js). Uma ferramenta de IA que adiciona o prefixo para fazer um erro sumir acabou de publicar a chave.
Quais chaves são seguras no navegador?
| Chave | Segura no frontend? | Por quê |
|---|---|---|
| Chave publishable (anon) do Supabase | Sim, com RLS em todas as tabelas | Ela só identifica o projeto; as policies decidem o que ela pode acessar |
| Chave secret (service role) do Supabase | Nunca | Ela ignora todas as policies de row level security |
Chave publicável do Stripe (pk_…) | Sim | Ela foi feita para o navegador e, sozinha, não consegue ler sua conta nem movimentar dinheiro |
Chave secreta do Stripe (sk_…) | Nunca | Ela pode criar cobranças e reembolsos e ler todos os dados de pagamento |
| Chaves de API da OpenAI, da Anthropic e de outras IAs | Nunca | Qualquer pessoa pode gastar seu crédito com ela |
| Strings de conexão de email, SMS e banco de dados | Nunca | Qualquer pessoa pode enviar mensagens em seu nome ou ler seus dados |
O Supabase é explícito sobre a segunda linha: “Uma chave secret vazada expõe todos os dados do seu projeto”, e as chaves secret “ignoram todas as políticas de Row Level Security que você tem. Nunca coloque uma num navegador, num aplicativo distribuído ou no controle de versão” (Supabase).
Como encontrar chaves expostas?
Pesquise no site em produção. Abra seu app, abra as ferramentas de desenvolvedor do navegador, vá até a aba Sources (ou Debugger) e pesquise em todos os arquivos por sk_, service_role, secret, api_key, token e os nomes dos serviços que você usa. Confira também a aba Network: uma requisição que sai do navegador direto para uma API paga está carregando a chave dela.
Pesquise no código e no histórico. Procure variáveis de ambiente com prefixo público (VITE_, NEXT_PUBLIC_, EXPO_PUBLIC_) que guardem qualquer coisa além de identificadores públicos. Depois pesquise no histórico do git, não só nos arquivos atuais: uma chave que foi commitada e depois apagada continua no histórico, e continua válida.
Ative o secret scanning. Se o código está no GitHub, ative o secret scanning e o push protection no repositório. Eles sinalizam formatos de chave conhecidos nos commits e bloqueiam o push de chaves novas.
O que fazer quando você encontra uma?
Siga esta ordem:
- Rotacione a chave. Crie uma chave nova no dashboard do provedor e revogue a antiga. Parta do princípio de que a chave antiga foi copiada; você não tem como saber que não foi.
- Avalie o estrago. Olhe o uso e os logs do provedor desde que a chave ficou exposta: gastos inesperados com APIs de IA, emails que você não enviou, leituras do banco de dados vindas de lugares desconhecidos.
- Mova a chamada para o servidor. O navegador chama o seu servidor (uma Supabase Edge Function, um route handler do Next.js, qualquer backend pequeno), e só o servidor guarda a chave. O servidor também decide quem pode fazer a chamada e com que frequência.
- Adicione limites. Defina tetos de gasto ou alertas de orçamento nas APIs pagas e rate limits nos seus próprios endpoints, para que um erro futuro custe pouco.
O passo 3 é o que as ferramentas de IA pulam, porque ele exige uma parte no servidor que o protótipo não tinha. Normalmente é uma mudança pequena: uma função por serviço externo.
Perguntas frequentes
É seguro colocar uma chave de API num app Vite ou React?
Só se a chave foi feita para ser pública, como a chave publishable do Supabase ou a chave publicável do Stripe. Tudo que tem prefixo VITE_ ou NEXT_PUBLIC_ acaba no JavaScript enviado a todo visitante, então as chaves secretas precisam ficar no servidor.
O que acontece se minha chave de API da OpenAI for exposta?
Qualquer pessoa que a copiar pode fazer requisições cobradas na sua conta até você revogá-la. Revogue e substitua a chave, confira seu uso em busca de gastos inesperados e mova as chamadas para um endpoint no servidor que guarde a chave nova.
Apagar a chave do código resolve o vazamento?
Não. A chave continua válida, continua no seu histórico do git e talvez já tenha sido copiada. Rotacione-a primeiro no dashboard do provedor; removê-la do código vem depois.