O que aconteceu
Com base no resumo da SafeState sobre a análise dos pesquisadores, o ataque foi mais ou menos assim:
- O site da Polymarket carregava um script de monitoramento de usuários reais do CDN da DebugBear. É uma configuração comum. Milhares de sites fazem o mesmo com dezenas de fornecedores.
- O atacante substituiu esse arquivo por JavaScript malicioso. Como o navegador buscava o arquivo direto do fornecedor, todos os visitantes receberam a nova versão imediatamente.
- O script verificava se havia uma sessão ativa da Polymarket, lia do armazenamento do navegador os dados da conta, os detalhes da carteira e as credenciais da API de trading, e depois usava o próprio fluxo de assinatura da Polymarket para mover posições ou vender ativos para uma carteira do atacante.
O detalhe que merece reflexão: os pesquisadores observaram que carteiras de hardware e senhas fortes não ajudaram, porque o script nunca precisou de uma chave privada. Ele agia como o usuário logado, de dentro da própria sessão do usuário no navegador.
A correção da Polymarket, segundo a mesma reportagem, foi um commit em produção que removeu o script do fornecedor. O trading voltou na mesma tarde. A SafeState também observa que este não foi o primeiro incidente com scripts de fornecedores a atingir a plataforma neste ano.
Por que isso importa para o seu app
Uma tag script apontando para cdn.some-vendor.com roda com o mesmo poder que o seu próprio código. Ela pode ler o DOM, ler localStorage e sessionStorage, chamar sua API com as credenciais do usuário e mudar o que a página exibe. Não existe sandbox entre "o seu código" e "o snippet de analytics que você colou na semana do lançamento".
Isso é especialmente relevante para apps lançados às pressas e apps feitos com IA, porque:
- Os scripts se acumulam. Cada prompt de "adicione analytics", "adicione um balão de chat" ou "adicione rastreamento de erros" costuma acrescentar mais uma tag. Pouca gente remove depois.
- Os tokens ficam no armazenamento do navegador. Muitos templates iniciais guardam o token de sessão ou de API no localStorage, onde qualquer script da página consegue lê-lo.
- Normalmente não há Content-Security-Policy. Sem ela, qualquer script injetado ou trocado pode carregar mais código de qualquer lugar e enviar dados para qualquer lugar.
Você não consegue auditar os pipelines de build dos seus fornecedores. Mas consegue limitar o estrago que um script malicioso pode fazer.
Como verificar seu app
1. Liste todos os scripts que suas páginas carregam. Abra seu app, depois o DevTools, a aba Network, filtre por JS e recarregue. Ou rode isto no console em cada página importante:
[...document.scripts].map(s => s.src || '(inline)').filter(Boolean)Anote cada domínio que não é seu. Faça isso também nas páginas logadas, não só no site de marketing. Gerenciadores de tags podem carregar outros scripts que não aparecem no código-fonte HTML.
2. Verifique quais dessas tags têm o atributo integrity. No console:
[...document.querySelectorAll('script[src]')]
.filter(s => !s.src.startsWith(location.origin))
.map(s => ({ src: s.src, sri: !!s.integrity }))3. Confira seus headers de resposta. Rode curl -sI https://yourapp.com e procure por Content-Security-Policy. Se não estiver lá, ou se contiver script-src * ou 'unsafe-inline' sem nonces, ela não está limitando muita coisa.
4. Verifique onde sua sessão fica guardada. No DevTools, olhe em Application as seções Local Storage e Session Storage. Se houver ali um access token, refresh token ou API key, qualquer script da página consegue lê-lo, que foi exatamente o que o payload da Polymarket fez.
Como corrigir
Remova o que você não precisa. Este é o passo de maior valor. As recomendações da SafeState para operadores começam por manter um inventário de scripts de terceiros e retirar tags não essenciais das páginas de conta, checkout e transações. Suas páginas de login, cobrança e configurações raramente precisam de uma ferramenta de heatmap.
Fixe e verifique o que mantiver com Subresource Integrity (SRI). Se um fornecedor oferece arquivos versionados, referencie uma versão específica e adicione um hash. Se o arquivo mudar, o navegador se recusa a executá-lo:
<script
src="https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js"
integrity="sha384-REPLACE_WITH_REAL_HASH"
crossorigin="anonymous"></script>Gere o hash você mesmo a partir do arquivo exato que revisou:
curl -s https://cdn.example-vendor.com/sdk/4.2.1/sdk.min.js \
| openssl dgst -sha384 -binary | openssl base64 -ATenha em mente o trade-off: o SRI quebra scripts que os fornecedores atualizam no lugar, em uma URL sem versão, algo comum em snippets de monitoramento e analytics. Para esses, ou você hospeda uma cópia fixada que atualiza de forma deliberada, ou aceita que está confiando no arquivo ao vivo do fornecedor e o mantém fora das páginas sensíveis.
Adicione uma Content-Security-Policy. A CSP diz ao navegador quais origens podem servir scripts e para quais origens a página pode enviar dados. Um ponto de partida para um app Next.js ou Express pode ser assim:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example-vendor.com;
connect-src 'self' https://api.yourapp.com;
frame-ancestors 'none';
base-uri 'self';
object-src 'none'Seja realista sobre o que a CSP oferece aqui: se o domínio do próprio fornecedor está liberado, a CSP não vai impedir um arquivo malicioso servido por ele. O que a CSP faz é impedir que esse script puxe código de novos domínios ou envie dados roubados para endpoints arbitrários que não estejam em connect-src. Implante primeiro com Content-Security-Policy-Report-Only para ver o que quebra. Nosso guia sobre como adicionar uma Content-Security-Policy explica isso passo a passo.
Tire os tokens de sessão do alcance do JavaScript. Mova os tokens de sessão para cookies marcados como HttpOnly, Secure e SameSite, para que os scripts da página não consigam lê-los. Isso não impede que um script malicioso faça requisições como o usuário enquanto a página está aberta, mas impede que os tokens sejam roubados e reutilizados em outro lugar. Veja as flags de cookie Secure, HttpOnly e SameSite.
Mantenha suas próprias chaves de frontend limpas. Se um script consegue ler seu bundle, consegue ler qualquer segredo que você tenha incluído nele, e bots já estão caçando chaves vazadas e arquivos .env. Confira nosso guia sobre API keys expostas em JavaScript no lado do cliente, garanta que você não está publicando source maps em produção e, se já levou um susto, nosso post sobre como rotacionar os segredos do seu app sem downtime explica a limpeza.
Checklist final
Antes de fechar o DevTools, garanta que você:
- Listou todos os scripts de terceiros das suas páginas públicas e logadas.
- Removeu os scripts que não usa mais, principalmente das páginas de login, cobrança e conta.
- Fixou versões e adicionou hashes de integridade onde os fornecedores permitem.
- Hospedou você mesmo, ou manteve fora das páginas sensíveis, os scripts que não podem ser fixados.
- Publicou uma Content-Security-Policy com script-src e connect-src restritos.
- Mantém os tokens de sessão em cookies HttpOnly, e não no localStorage.
- Vai refazer esta auditoria sempre que alguém (ou algum agente de IA) adicionar uma nova tag.
Descubra onde você está
Se quiser uma referência rápida, o AppSafe verifica seus headers de segurança, incluindo se há uma Content-Security-Policy configurada, e o scan completo verificado analisa problemas de frontend como Subresource Integrity e bibliotecas JavaScript vulneráveis. Veja como é um relatório no relatório de exemplo, ou combine isso com nosso checklist pré-lançamento para apps feitos com IA.
A Polymarket encontrou a causa cerca de uma hora depois de suspender o trading. Muitas equipes pequenas levariam muito mais tempo para perceber que um script mudou. Rode um scan gratuito do AppSafe no seu app hoje e descubra onde você está.
