Chaves da API em builds de frontend: como encontrar e corrigir vazamentos
Chaves de API em builds de frontend podem expor seus dados. Aprenda a encontrar segredos empacotados, movê-los para o servidor e rotacionar com segurança.

O que significa vazar segredos através de um build de frontend
Um build de frontend é o conjunto de arquivos que seus usuários baixam para executar seu app no navegador. Normalmente inclui JavaScript empacotado (frequentemente um arquivo grande), CSS, imagens e outros assets estáticos. Ferramentas de build pegam seu código-fonte e empacotam para que o navegador carregue rapidamente.
Um vazamento acontece quando algo que você pretendia manter privado é incorporado nesses arquivos baixáveis. Se é enviado ao navegador, qualquer pessoa pode vê-lo abrindo o código da página, abrindo o DevTools ou baixando o bundle e procurando por ele.
Segredos são qualquer coisa que permita a alguém agir como seu app ou acessar sistemas protegidos. Exemplos comuns incluem chaves de API e tokens de serviço (Stripe, OpenAI, provedores de mapas, serviços de e-mail), strings de conexão de banco de dados, segredos de assinatura de JWT, chaves privadas de criptografia, URLs privadas de webhooks, endpoints administrativos e URLs internas que contornam autenticação normal.
Por isso chaves de API em builds de frontend devem ser tratadas como informação pública. Minificação e ofuscação não ajudam. Se o navegador precisa receber o valor para usá-lo, um atacante também pode recebê-lo.
O impacto geralmente é direto: alguém copia sua chave e aumenta sua fatura, esgota limites de taxa fazendo com que usuários reais recebam erros, ou usa sua conta para enviar spam a um provedor. Se o segredo libera acesso a dados, pode ocorrer uma violação real (registros de clientes, arquivos ou ações administrativas). Custos e danos muitas vezes começam pequenos e escalonam rápido, especialmente quando a chave vazada tem permissões amplas.
Formas comuns de segredos aparecerem no código do cliente
A maioria dos vazamentos não é “hack”. Vem de escolhas normais de build e configuração que, acidentalmente, tratam segredos como configurações públicas.
Injecção em tempo de build transforma .env em código publicado
Ferramentas como Vite, Next.js e Create React App podem substituir variáveis de ambiente em tempo de build. Se um segredo é referenciado no código cliente, o bundler frequentemente o troca por uma string literal. Um valor que vivia com segurança em um .env local pode acabar incorporado no JavaScript de produção.
Uma armadilha comum é pensar “está em uma env var, então está seguro”. Só é seguro se for usado no servidor e nunca incluído nos bundles do cliente.
Prefixos “públicos” de env são para valores públicos
Frameworks usam prefixos para marcar variáveis que podem ser expostas ao navegador (por exemplo: VITE_, NEXT_PUBLIC, REACT_APP). Esses são adequados para configurações não sensíveis, como uma flag de recurso ou um ID público de analytics.
Eles não são lugar para qualquer coisa que possa gerar custos, acessar dados privados ou conceder permissões elevadas: chaves de API de terceiros que criam cobranças, tokens administrativos, chaves de assinatura, URLs de banco de dados, credenciais de serviço e segredos de webhook.
Se você coloca um segredo atrás de um prefixo público, está pedindo explicitamente ao sistema de build para publicá-lo.
Strings hardcoded e arquivos de configuração “úteis”
Segredos também escapam via constantes, objetos de config e arquivos JSON (por exemplo, config.ts, firebaseConfig ou settings.json). Podem parecer configuração inofensiva durante a revisão.
Isto é especialmente comum em protótipos gerados por IA: ferramentas costumam colar um exemplo funcional com a chave inline para que a demo “funcione”. Se esse código for publicado, a chave se torna pública.
Source maps facilitam a descoberta
Source maps não criam o vazamento, mas podem facilitar muito a localização. Se os source maps estão públicos, um atacante pode buscar no código legível por tokens, endpoints e strings que pareçam segredo em vez de vasculhar bundles minificados.
Se você suspeita que um segredo foi exposto, assuma que já foi comprometido. Planeje movê-lo para o servidor e rotacioná-lo.
Maneiras rápidas de detectar variáveis de ambiente e chaves expostas
Você pode confirmar um vazamento em minutos sem mudar código. Comece com o que o navegador já tem.
-
Observe requisições de rede no DevTools. Abra a aba Network e percorra os fluxos que chamam serviços de terceiros (login, checkout, busca, upload de arquivos). Abra uma requisição e verifique Headers e Preview/Response. Vazamentos costumam aparecer como query params (como
?api_key=), um headerAuthorization: Bearer ...ou um body JSON que inclui um token. -
Busque o que você realmente publica. Na pasta de saída do build (geralmente
dist/oubuild/), rode uma busca de texto nos arquivos.jspor padrões comosk-,api_key,apikey,secret,token,Bearer,BEGIN PRIVATE KEY, além dos nomes dos seus fornecedores e URLs base (Stripe, OpenAI, Twilio, Supabase, etc.). -
Abra o bundle compilado e escaneie por strings suspeitas. Procure credenciais hardcoded, endpoints completos ou blobs de config que incluam chaves. Um sinal comum é configuração em runtime exposta em
window(por exemplowindow.__CONFIG__ouwindow.env) que contenha qualquer coisa mais sensível que IDs públicos. -
Verifique se source maps estão acessíveis em produção. Arquivos
*.mappúblicos podem revelar nomes de variáveis e estruturas de config originais, o que facilita o reaproveitamento.
Um teste prático: se você consegue copiar um token do DevTools e reproduzir a mesma requisição de outro perfil do navegador ou de um script, não é um valor seguro no cliente.
Planeje a limpeza antes de mudar código
Uma vez confirmado o vazamento, não comece a remover variáveis ou rotacionar tudo de uma vez. Um pouco de planejamento evita outages, logins quebrados e erros 401 confusos.
Comece listando cada sistema externo que seu app usa e onde as credenciais vivem hoje: pagamentos, e-mail, armazenamento de arquivos, analytics, APIs de IA e qualquer outra coisa. Inclua staging, preview e dev local. Vazamentos muitas vezes acontecem em builds de preview porque parecem descartáveis.
Depois, separe o que pode ser chamado pelo navegador do que deve ser apenas no servidor. Tudo que pode gastar dinheiro, ler dados privados, escrever no banco ou contornar limites de taxa não deve ser chamado diretamente do cliente. Se um serviço oferece uma chave publicável para navegadores, trate-a diferente de uma chave secreta.
Crie um inventário simples que a equipe possa compartilhar:
- Nome da chave como usada no código (por exemplo,
STRIPE_SECRET_KEY) - Serviço e conta/projeto a que pertence
- Ambientes (dev, staging, prod)
- Onde aparece (repo, CI, configurações de hosting, arquivos buildados)
- Nível de risco (baixo para IDs públicos, alto para segredos)
Depois decida o que rotacionar imediatamente versus depois das mudanças de código. Rotacione agora se a chave vazada concede escrita, tem escopos amplos ou pode drenar créditos. Adie rotação se isso quebrar a produção antes de você ter uma substituição server-side pronta.
Defina uma janela curta de freeze (mesmo 30 a 60 minutos) onde ninguém faz merge, deploy ou muda env vars de hosting enquanto vocês coordenam. Atribua um dono para cada serviço e concordem na ordem: envie as mudanças no servidor primeiro, rotacione em seguida, então redeploy e verifique.
Passo a passo: auditar, remover e testar novamente seu build
Trate isso como um incidente: encontre o que vazou, pare o vazamento e prove que sumiu.
1) Audite o que existe (repo e saída do build)
Procure no seu código-fonte e nos assets compilados (os arquivos finais que seus usuários baixam). Não pare no repositório. Arquivos de build podem esconder segredos em bundles minificados.
Um fluxo simples:
- Escaneie por padrões de aparência de segredo: tokens longos, prefixos de provedores (por exemplo,
sk_,xoxb-) e stringsBearer. - Verifique uso de env:
process.env,import.meta.enve quaisquer variáveis públicas do framework. - Busque no JS gerado por strings óbvias: seu domínio de API, prefixos de chave ou blobs JSON com credenciais.
- Confirme onde aparece: no código-fonte, na config ou apenas após o passo de build.
- Anote cada ocorrência e onde foi encontrada antes de mudar qualquer coisa.
2) Confirme o que é realmente sensível
Nem todo valor com cara de chave é perigoso. Alguns serviços usam chaves publicáveis feitas para navegadores, enquanto outros dão acesso total à conta.
Faça duas perguntas:
- O que essa credencial pode fazer?
- Um atacante pode usá-la a partir da própria máquina?
Se a resposta for sim e sim, trate como sensível.
3) Remova do cliente e substitua por uma chamada ao servidor
Apague o segredo do código cliente e de qualquer env de tempo de build que acabe no navegador. Substitua a chamada cliente→fornecedor por um endpoint no servidor que use o segredo no servidor. O frontend deve chamar seu endpoint, não o fornecedor diretamente.
4) Reteste com uma chave nova (primeiro em não produção)
Crie uma chave nova, teste ponta a ponta em staging ou preview e só então troque em produção. Rebuild e re-escaneie a saída para confirmar que o segredo realmente sumiu.
Mova segredos para o servidor sem quebrar o app
A correção mais segura não é “esconder melhor no JavaScript”. É parar de enviar o segredo ao navegador.
O padrão básico: um proxy no servidor
Faça o cliente chamar um endpoint do seu backend (ou uma função serverless). Esse endpoint conversa com a API de terceiros e adiciona o segredo no servidor. O navegador nunca vê a chave.
Uma abordagem simples que mantém o comportamento da UI:
- Substitua a chamada direta do frontend ao provedor por uma chamada ao seu próprio endpoint.
- No servidor, leia o segredo de variáveis de ambiente acessíveis apenas no servidor.
- Retorne apenas os dados que a UI precisa, não a resposta completa upstream.
Evite construir um proxy aberto. Valide entradas no servidor: permita apenas as rotas necessárias, verifique campos obrigatórios e bloqueie URLs ou headers inesperados. Se seu endpoint aceitar uma “URL de destino” do cliente, você recriou o vazamento em nova forma.
Prefira tokens de curta duração quando possível
Se o terceiro oferecer, gere tokens de curta duração no servidor e envie só esse token ao cliente. Tokens que expiram em minutos são mais seguros do que chaves de longa duração embutidas num bundle.
Combine isso com controles básicos no servidor, como rate limiting e logging de requisições, para que abusos apareçam rápido (picos súbitos, falhas repetidas, payloads incomuns).
Mantenha o código cliente limitado a identificadores públicos (como um ID de projeto público) e flags não sensíveis (por exemplo useSandbox: true). Tudo que concede acesso ou pode criar cobranças pertence ao servidor.
Rotacione chaves com segurança e mínimo downtime
Rotacionar uma chave vazada não é só “gerar uma nova e colar”. Se você revogar a chave antiga cedo demais, usuários reais recebem erros. Se deixar ativa por muito tempo, o vazamento continua a ser abusado. Busque uma sobreposição curta e controlada.
A abordagem mais segura é rotacionar em duas fases: introduza a nova chave primeiro, confirme que o tráfego a usa, então revogue a antiga.
Sequência de rotação de baixo risco
Faça isso quando puder monitorar logs.
- Crie uma nova chave no dashboard do provedor. Nomeie claramente (por exemplo:
prod-2026-01-rotation). - Adicione a nova chave a um cofre de segredos do lado do servidor (não ao build do frontend). Mantenha a chave antiga ativa por enquanto.
- Faça deploy de uma versão que use a nova chave.
- Verifique uso nos logs do provedor e nos logs do seu app.
- Revogue a chave antiga após uma janela curta de sobreposição (normalmente 15 a 60 minutos, mais se deploys forem lentos ou se houver jobs de longa duração).
Defina um lembrete para revogar a chave antiga. Equipes frequentemente esquecem, especialmente durante um incidente.
Não esqueça dos “consumidores escondidos”
Antes de revogar, certifique-se de que atualizou:
- Jobs em background e tarefas agendadas
- Webhooks e integrações de terceiros que chamam sua API
- Apps móveis (podem demorar se usuários não atualizarem)
- Ambientes de staging que acidentalmente compartilham chaves de produção
- Setups de teste local que ainda usam a chave antiga
Após o deploy, monitore taxas de erro e falhas de autenticação de perto. Se algo quebrar, faça rollback rapidamente ou estenda a sobreposição enquanto encontra o caller perdido.
Erros comuns que mantêm o vazamento vivo
Se você vê um valor no navegador (View Source, DevTools, network requests, JS bundlado), um atacante também pode ver.
- Minificação e ofuscação não protegem segredos. Uma chave embutida num bundle continua sendo uma chave, mesmo que esteja dividida entre variáveis ou renomeada.
- Tokens de longa duração em
localStorageousessionStoragesão fáceis de roubar com XSS. Prefira sessões de curta duração emitidas pelo servidor (geralmente via cookies HTTP-only) e mantenha credenciais reais no servidor. - Endpoints de debug e rotas admin ficam abertos. Qualquer coisa que contorne auth ou despeje dados durante testes pode se tornar caminho para produção.
- Logs de erro no cliente podem vazar segredos. Evite logar headers completos de requisição, tokens ou dumps de config no navegador.
- CORS não é uma fronteira de segurança. Ele só limita quais navegadores podem ler respostas. Não impede chamadas diretas de scripts, servidores ou ferramentas como curl.
Checklist rápido antes do deploy
Use isto imediatamente antes de enviar para produção.
5 checagens que previnem a maioria dos vazamentos
- Confirme que o bundle cliente está limpo: Busque na saída do build (não apenas no código-fonte) por padrões de chave (por exemplo,
sk_,AIza,Bearer,-----BEGIN, ou o nome do seu provedor). Também confirme que você não está usando prefixos públicos de env (comoNEXT_PUBLIC_ouVITE_) para algo que deveria ser privado. - Trate source maps como sensíveis: Se mantiver source maps em produção, restrinja acesso. Se não precisar, desative-os para builds de produção.
- Mova segredos para trás da fronteira do servidor: Qualquer chamada que precise de segredo deve passar pelo seu servidor (ou função serverless). O navegador só deve enviar intenção do usuário e receber resultados seguros.
- Tranque endpoints do servidor: Valide entradas, cheque autenticação quando necessário e aplique limites de taxa.
- Rotacione chaves e monitore abuso: Crie chaves novas primeiro, faça o deploy da mudança, então revogue as antigas. Monitore picos de tráfego ou aumentos de custo.
Um exemplo simples: se seu frontend chama um provedor de mapas ou IA diretamente, essa chave será copiada e reutilizada por estranhos. Em vez disso, o navegador chama seu endpoint de backend, e o backend chama o provedor com o segredo.
Exemplo: um protótipo gerado por IA que publicou uma chave real
Um fundador cria um MVP rápido em Lovable e o deploya no mesmo dia. O app chama uma API paga de terceiros (como um LLM, mapas, e-mail ou analytics) e a chave está definida como variável de ambiente. O problema é que a ferramenta de build copia esse valor no bundle do navegador, então a chave fica dentro do JavaScript enviado.
Um usuário curioso abre o DevTools, busca por “key” ou pelo nome do provedor na aba Sources e encontra a chave num arquivo minificado. Copia e faz requisições do próprio script. Em horas, o uso dispara, custos sobem e o dashboard do provedor mostra tráfego que não corresponde a usuários reais.
A correção é simples, mas a ordem importa:
- Mova a chamada da API para uma rota de servidor (ou função serverless) para que o navegador nunca veja o segredo.
- Adicione proteção básica nessa rota: checagens de auth, limites de taxa e validação de entrada.
- Rotacione a chave exposta e revogue a antiga após uma sobreposição curta.
- Revise os logs do provedor em busca de IPs suspeitos, endpoints incomuns e tráfego fora do horário normal.
- Adicione alertas e limites de gasto para ser avisado antes que os custos disparem.
Depois da mudança, a UI continua acionando a mesma funcionalidade. Só que agora chama seu endpoint backend em vez do provedor diretamente. O backend lê a chave de variáveis de ambiente do servidor e conversa com a API de terceiros em nome do usuário. No navegador, não há nada valioso para roubar.
Próximos passos se seu código é confuso ou gerado por IA
Se seu app foi gerado com ferramentas como v0, Cursor, Replit, Bolt ou Lovable, assuma que a mesma chave pode ter sido copiada em vários lugares: um .env, um helper de config, um log “temporário” e o bundle do cliente. Por isso correções rápidas falham: você remove uma cópia, mas outra ainda é publicada.
Concentre-se em todos os caminhos que o valor pode tomar, não só o óbvio. Isso inclui injeção de env em tempo de build, objetos de config empacotados, funções serverless e fluxos de auth que passam tokens pelo navegador.
Uma abordagem prática quando o repositório é pouco confiável:
- Identifique os segredos mais críticos (pagamentos, e-mail, banco de dados, APIs administrativas).
- Busque no repositório por padrões de chave e nomes de variáveis de ambiente, e depois verifique também a saída do build.
- Trace como as requisições são feitas: do navegador direto ao fornecedor, ou via seu servidor.
- Decida a nova casa server-side para cada segredo (rota API, serviço backend, proxy).
- Planeje a rotação de chaves após a mudança de código para evitar surpresas.
Se você herdou um protótipo gerado por IA e precisa de uma intervenção rápida focada em segurança, FixMyMess (fixmymess.ai) faz diagnóstico e remediação de codebases para problemas como segredos empacotados, auth quebrada e padrões de requisição inseguros; eles oferecem uma auditoria de código gratuita para mapear o que está exposto antes de começar a rotacionar chaves.
Perguntas Frequentes
What counts as a “secret” in a frontend build?
Se o navegador precisa do valor para rodar, ele é efetivamente público. Qualquer coisa que possa gastar crédito, ler dados privados, escrever no banco de dados ou assinar/verificar tokens deve ser tratada como segredo e mantida no servidor.
Does minification or obfuscation protect API keys in JavaScript bundles?
Não. A minificação só altera a aparência do código, não o que ele contém. Qualquer pessoa pode baixar seu bundle e buscar por strings, então uma chave embutida em JavaScript continua exposta.
Are NEXT_PUBLIC_, VITE_, and REACT_APP_ environment variables safe to use for secrets?
Esses prefixos são explicitamente para valores que podem ser expostos ao navegador. Use-os apenas para configurações não sensíveis, como IDs públicos ou flags de UI, e nunca para chaves secretas, tokens de serviço ou URLs de banco de dados.
How can I quickly tell if a key is leaking without changing code?
Abra o site, use o DevTools e verifique as requisições de rede por query params, headers ou corpos de requisição que contenham tokens. Depois, procure nos arquivos gerados (built output) por padrões óbvios como “Bearer”, “api_key”, nomes de provedores ou prefixos de chave.
Why do public source maps make secret leaks worse?
Source maps não criam o vazamento, mas tornam muito mais fácil encontrar e reutilizar por revelar o código legível e nomes de variáveis. Se você mantiver source maps em produção, restrinja o acesso ou desative-os para builds de produção quando não precisar.
What should I do first after I find an exposed key?
Assuma que foi comprometido e pare o vazamento antes de gastar tempo debatendo. Capture onde o encontrou, identifique o que ele pode fazer e planeje a mudança para mover o segredo para o servidor e rotacioná-lo sem quebrar a produção.
What’s the safest way to move a secret out of the frontend without breaking features?
Substitua a chamada direta do navegador ao fornecedor por um endpoint no seu backend (ou função serverless) que chama o fornecedor usando variáveis de ambiente acessíveis apenas no servidor. O frontend deve enviar intenção do usuário e receber apenas os dados necessários.
Is it okay to store tokens in localStorage or sessionStorage?
É arriscado: qualquer bug de XSS pode roubar tokens em localStorage ou sessionStorage e reproduzi-los. Prefira sessões gerenciadas pelo servidor (cookies HTTP-only) e credenciais de curta duração quando possível; evite armazenar segredos de longa vida no navegador.
How do I rotate a leaked key without downtime?
Use uma abordagem em duas fases: primeiro, implante o código que suporta a nova chave, confirme que o tráfego a está usando, e então revogue a chave antiga após uma sobreposição curta. Revogar cedo demais gera erros para usuários reais; esperar demais permite abuso contínuo.
Do AI-generated prototypes leak secrets more often, and can FixMyMess help?
Sim. Código gerado por IA costuma colar chaves que funcionam, inseri-las em configs temporários ou referenciar variáveis de ambiente no cliente para que acabem no build. Se o repositório for difícil de confiar, FixMyMess pode executar uma auditoria gratuita de código, traçar caminhos de vazamento e entregar uma remediação focada em segurança — frequentemente em 48–72 horas, e em casos urgentes um plano de rebuild pode começar em cerca de um dia.