Se existe um erro que aparece em quase todo app feito com IA que chega para nós, é este: uma chave secreta escrita dentro do código. A chave da OpenAI, da Stripe, do serviço de e-mail ou a chave administrativa do banco de dados, colada num arquivo que vai parar no navegador do usuário ou num repositório público.
É um erro que custa caro rápido. Chave de modelo de IA exposta vira fatura. Chave de pagamento exposta pode virar estorno ou fraude. Chave administrativa do banco exposta significa que qualquer pessoa pode ler, alterar ou apagar todos os dados.
Por que a IA faz isso
A ferramenta de IA quer que a funcionalidade funcione agora. Você pede “integra o pagamento com a Stripe”, ela precisa de uma chave para testar, e o caminho mais curto é colocar a chave no lugar onde ela é usada. O código funciona, você vê o resultado e segue em frente.
O problema é que, em muitos apps modernos, o código do front-end (as telas) é baixado inteiro para o navegador de quem acessa. Qualquer coisa escrita ali pode ser lida por qualquer pessoa que abra as ferramentas de desenvolvedor do navegador. Não exige nenhum conhecimento avançado.
Existe ainda uma armadilha específica: frameworks como Next.js e Vite usam prefixos (NEXT_PUBLIC_, VITE_) para indicar quais variáveis vão para o navegador. Quando a IA põe a chave secreta numa variável com esse prefixo para “fazer funcionar”, a chave fica pública mesmo estando num arquivo de configuração.
Como descobrir se a sua chave está exposta
Três verificações rápidas que você mesmo consegue fazer:
- Procure no projeto. Busque por trechos típicos de chave:
sk-,sk_live,service_role,secret,apiKey,token. Se aparecer um valor longo e aleatório escrito direto no código, é um sinal. - Abra o app no navegador e inspecione. Nas ferramentas de desenvolvedor, aba Rede (Network), veja as chamadas que o app faz. Se aparecer uma chamada direto para a API da OpenAI, da Stripe ou de outro serviço pago saindo do navegador, a chave está indo junto.
- Veja se o repositório é público. Se o código está no GitHub como público, tudo o que já foi escrito nele, inclusive em versões antigas, está à vista. O GitHub tem varredura de segredos (secret scanning) que avisa sobre alguns formatos conhecidos, mas não cobre tudo.
O que fazer nos primeiros 30 minutos
Se encontrou uma chave exposta, a ordem importa:
- Gere uma chave nova no painel do fornecedor.
- Desative a chave antiga. Só apagar do código não adianta: ela já pode ter sido copiada. Considere vazada toda chave que esteve exposta, mesmo que por pouco tempo.
- Olhe o uso recente no painel do fornecedor. Uso fora do padrão é sinal de que alguém já aproveitou.
- Coloque a chave nova no lugar certo: numa variável de ambiente do servidor, configurada no painel da hospedagem, nunca num arquivo versionado.
- Tire a chave antiga do histórico do repositório, se ele for público. Apagar o arquivo deixa a chave visível nas versões anteriores.
Onde a chave deve ficar
A regra é simples: segredo só existe no servidor. O navegador pede ao seu servidor (“gere um resumo deste texto”) e o servidor, que tem a chave, fala com o fornecedor. O usuário nunca vê a chave.
Na prática, isso significa:
- Chamadas a serviços pagos (modelos de IA, pagamento, envio de e-mail e SMS) passam por uma função no servidor: uma rota de API, uma edge function, uma serverless function.
- As chaves ficam em variáveis de ambiente configuradas na hospedagem e num arquivo
.envque não vai para o repositório (ele entra no.gitignore). - Cada ambiente (teste e produção) tem a sua chave, e cada fornecedor tem um teto de gasto configurado.
O caso do Supabase
O Supabase tem duas chaves, e a diferença entre elas é crítica. A chave anon (ou publicável) foi feita para ficar no navegador; ela só é segura se as políticas de Row Level Security estiverem ligadas em todas as tabelas. A chave service_role ignora todas as regras e dá acesso total ao banco. Ela nunca pode ir para o navegador. Quando encontramos a service_role no front-end, tratamos como incidente.
Como evitar que aconteça de novo
- Diga à IA onde a chave vai. Ao pedir uma integração, peça explicitamente que a chamada seja feita no servidor e que a chave venha de variável de ambiente.
- Ligue a varredura de segredos no repositório e um verificador antes de cada envio de código.
- Use teto de gasto e alertas em todo fornecedor que cobra por uso. É o que transforma um vazamento caro num susto barato.
- Tenha alguém revisando o código antes de ir ao ar. É o tipo de erro que uma revisão humana pega em minutos.
Escrito pela equipe da Grimpo com apoio de inteligência artificial e revisado por uma pessoa. Viu um erro ou quer sugerir um tema? Fale com a gente.
Perguntas frequentes
Apagar a chave do código resolve?
Não. Se a chave ficou exposta em algum momento, considere que ela vazou. O certo é gerar uma chave nova no painel do fornecedor, desativar a antiga e só então tirar a antiga do código e do histórico.
A chave anon do Supabase pode ficar no navegador?
Pode, ela foi feita para isso, desde que as políticas de Row Level Security estejam ligadas. A que nunca pode ir para o navegador é a service_role, que ignora todas as regras de acesso.
Variável de ambiente com prefixo NEXT_PUBLIC ou VITE é segura?
Não para segredo. Esses prefixos existem justamente para mandar o valor para o navegador. Tudo que começa com eles é público.
Fontes
- Supabase: chaves de API
- Next.js: variáveis de ambiente
- Vite: variáveis de ambiente
- GitHub: secret scanning
- OWASP: Secrets Management Cheat Sheet
Continue lendo
Criei um app com IA. Ele está pronto para ir ao ar?
Funcionar na sua tela não é o mesmo que aguentar cliente de verdade. Doze perguntas para responder antes de publicar um app…
Supabase e Firebase sem regras de acesso: quando qualquer usuário lê o banco inteiro
O banco que a IA escolheu deixa o navegador falar direto com os dados. Sem as regras certas, um usuário vê os…
Funciona no meu computador, quebra no ar: por que isso acontece com apps feitos com IA
Variáveis de ambiente, banco diferente, dependências soltas e build que ninguém testou. As cinco causas mais comuns e como evitar cada uma.



