Análise de Card Testing — VTEX¶
Ferramentas que leem a API da VTEX para investigar o ataque de card testing na loja useveggi.com.br: descobrir domínios de ataque novos, medir a taxa de recusa mês a mês e detalhar a infraestrutura por trás dos pedidos negados.
Onde fica: C:\Projetos\vtex-analise
Credenciais
Todos os scripts leem as credenciais do arquivo .env dessa pasta — VTEX_ACCOUNT, VTEX_APP_KEY e VTEX_APP_TOKEN. Não coloque credencial em outro lugar. O .gitignore já bloqueia o .env e os CSVs; não copie essa pasta para lugar público nem anexe o .env em e-mail.
O jeito fácil: os executáveis¶
Procurando a receita passo a passo?
Esta página explica o que cada executável faz. Para o roteiro na ordem, com o que fechar antes de cada um e o que fazer com o resultado, veja Passo a Passo da Rotina.
Não precisa abrir o PowerShell nem decorar comando nenhum. Na pasta C:\Projetos\vtex-analise há arquivos numerados. Dê dois cliques no que a situação pedir.
A rotina, do começo ao fim¶
TODA SEGUNDA 2 - dominio de ataque novo
│
├── "Nenhuma infraestrutura nova" ──► acabou
└── listou dominio ──► 5 - BLOQUEAR dominio novo
DIA 1 DO MES 3 - taxa de recusa
│
├── nenhum mes marcado ──► acabou
└── mes com <<< ──► 7 - INVESTIGAR mes suspeito
│
├── ja deu pra entender
│ ──► 5 ou 6 pra bloquear
│
└── preciso do motivo da
recusa e do CPF
──► 8 - ANALISE PROFUNDA
A CADA 3 MESES 9 - ATUALIZAR planilha do panorama
Qual executável usar¶
| Situação | Executável |
|---|---|
| Rotina de segunda-feira | 2 - SEMANAL - dominio de ataque novo.bat |
| Rotina do dia 1 do mês | 3 - MENSAL - taxa de recusa.bat |
O 3 marcou um mês com <<< |
7 - INVESTIGAR mes suspeito.bat |
O 7 não bastou — preciso do motivo da recusa, CPF, correlação |
8 - ANALISE PROFUNDA do periodo.bat |
| Descobri um domínio de ataque | 5 - BLOQUEAR dominio novo.bat |
| Descobri um e-mail ou CPF específico | 6 - BLOQUEAR ou LIBERAR email e CPF.bat |
| Vou mostrar o panorama para a VTEX | 9 - ATUALIZAR planilha do panorama.bat |
| Quero abrir a pasta de resultados | 4 - ABRIR a pasta de resultados.bat |
Todos param e mostram o erro
Nenhum executável fecha a janela na sua cara quando dá errado. Copie a mensagem e mande para o Claude — é o suficiente para descobrir o que houve.
Onde cada arquivo cai¶
Tudo que os programas geram vai para saida/, uma pasta por script, com o nome do script. A pergunta que se faz na frente da pasta — de onde veio este arquivo? — se responde sozinha pelo nome. Há um LEIA-ME.txt dentro de saida/ explicando pasta por pasta.
| Pasta | Vem de | O que tem |
|---|---|---|
clientes-travados/ |
executável 1 | As mensagens prontas, a lista de clientes e os descartados como bot |
vigia-dominios/ |
executável 2 | vigia-<data>.csv de cada rodada |
extrai-infra/ |
executável 7 | infra-*.csv, um por período investigado |
vtex-export-oms/ |
executável 8, etapa 1 | A coleta crua: 33 campos por pedido |
gerar-xlsx/ |
executável 8, etapa 2 | Card_Testing_VTEX.xlsx |
indice-pedidos/ |
executável 9, etapa 1 | Índice de todos os pedidos |
monta-planilha/ |
executável 9, etapa 3 | card-testing-2024-2026.xlsx, a planilha do panorama |
extrai-negados/, marca-cancelamento/, cruza-quarentena/, parcelas/, listas-de-pedidos/ |
scripts sem executável | Material das análises pontuais |
_arquivo-morto/ |
— | Sobras de agosto/2026. Nenhum script gera nem lê. Pode apagar |
Nunca apague a pasta extrai-infra
A planilha do panorama é montada juntando todos os infra-*.csv de lá. Apagar um arquivo faz aquele mês sumir do relatório.
Para quem for escrever script novo aqui
Grave com pp.pasta_de("seu-script", "x.csv") no Python ou pastaDe("seu-script", "x.csv") no Node. Script que lê a saída de outro passa a pasta do outro — assim a dependência entre eles fica escrita na própria chamada, como no monta-planilha.py, que lê de extrai-infra, indice-pedidos e marca-cancelamento.
7 — Investigar mês suspeito¶
Quando: o executável 3 marcou um mês com <<<.
Ele pergunta duas datas e mostra quem está por trás dos pedidos negados daquele período.
Formato ano-mês-dia. Para o mês de setembro inteiro: 2026-09-01 até 2026-09-30.
Mês inteiro leva alguns minutos — são duas consultas à VTEX por pedido.
O que sai e como ler¶
Sai um arquivo em saida\extrai-infra\infra-<data>-a-<data>.csv. Abra no Excel e olhe três colunas:
| Coluna | O que denuncia |
|---|---|
ip |
Muitos pedidos do mesmo IP = bot |
device |
Mesmo aparelho repetido = bot |
bin |
Vários cartões diferentes = teste de cartão |
A régua
Cliente de verdade tem 1 ou 2 tentativas recusadas. Bot tem dezenas.
Achou domínio suspeito → executável 5. Achou e-mail ou CPF específico → executável 6.
8 — Análise profunda¶
Quando: o 7 mostrou que há ataque, mas você precisa de mais para agir ou para levar à VTEX.
Traz 33 informações por pedido, contra 11 do executável 7. Só aqui aparecem:
- o motivo real da recusa, escrito pelo banco
- CPF, nome, telefone e cidade do titular
- o e-mail sem a máscara da VTEX (
-123b.ct.vtex.com.br) - quantos cartões diferentes cada CPF queimou — a prova do card testing
Pergunta as mesmas duas datas, roda em duas etapas e monta a planilha saida\gerar-xlsx\Card_Testing_VTEX.xlsx.
É lento — use em período curto
São três consultas por pedido, mais uma pausa entre elas. Rode no período que o 7 já apontou, nunca no ano inteiro. Para varrer meses, o caminho é o 7.
Feche a planilha no Excel antes de rodar
Se o Card_Testing_VTEX.xlsx estiver aberto, a coleta funciona mas a planilha não é gravada — e aí a coleta inteira precisa ser refeita.
9 — Atualizar a planilha do panorama¶
Quando: a cada 3 ou 4 meses, ou quando for mostrar o panorama do ataque para a VTEX.
A planilha saida\monta-planilha\card-testing-2024-2026.xlsx guarda a história toda do ataque. O executável pergunta a partir de qual mês faltam dados e roda as três etapas na ordem certa.
Nunca apague os arquivos infra-*.csv
A planilha é montada juntando todos eles. Apagar um arquivo faz aquele mês sumir do panorama, e a única forma de recuperar é rodar o 7 de novo naquele período.
Feche a planilha no Excel antes de rodar.
Por dentro — os comandos¶
Esta parte é a referência técnica, para manutenção ou quando algo sair do esperado. A rotina do dia a dia não precisa dela.
Como abrir o PowerShell¶
Tecla Windows, digite powershell, Enter. Para colar: botão direito do mouse (não é Ctrl+V).
1. Vigia de domínios — rode toda semana¶
É o único item que vale colocar na rotina. Descobre domínio de ataque novo antes que ele seja usado em volume.
Executável equivalente:
2 - SEMANAL - dominio de ataque novo.bat
cd "C:\Projetos\vtex-analise"
python vigia-dominios.py # últimos 7 dias
python vigia-dominios.py 30 # últimos 30 dias
Classifica cada domínio em três situações:
| Situação | Significado | Ação |
|---|---|---|
| JÁ COBERTO | O validador já bloqueia | Nada a fazer |
| PROVÁVEL REAL | MX em Google Workspace, Microsoft 365 ou Cloudflare | Não bloqueie — é cliente de verdade cujo cartão foi recusado |
| INFRA NOVA | Servidor desconhecido | Único que exige ação. O script já imprime o comando de bloqueio pronto para copiar |
Success
Se der "Nenhuma infraestrutura nova", está tudo em dia.
O comando impresso é o wrangler kv key put ... blocklist do Validador de e-mail — lembre que ele substitui a lista inteira.
2. Mapa mensal — taxa de recusa¶
Executável equivalente:
3 - MENSAL - taxa de recusa.bat
Mostra, mês a mês, quantos pedidos houve e quantos foram negados. Marca com <<< os meses acima de 60%.
Referência
Taxa normal de e-commerce: 10% a 15%. Acima de 50% é ataque.
3. Investigar um período específico¶
Quando o mapa mensal acusar um mês ruim e você quiser saber quem foi:
Executável equivalente:
7 - INVESTIGAR mes suspeito.bat
Gera saida/extrai-infra/infra-<data>-a-<data>.csv com IP, device, sessão, user-agent, bandeira, BIN e finais do cartão de cada pedido negado.
Warning
Para janela grande demora — são duas chamadas de API por pedido.
Se quiser só os e-mails, sem IP e cartão, é mais rápido:
Por que duas APIs
O OMS da VTEX esconde as recusas dentro do status "Cancelado". Só a API de Pagamentos tem o motivo real da negativa, o IP e o device — por isso o script cruza as duas.
O extrai-infra.py não traz o motivo da recusa
Ele chama a API de Pagamentos, mas extrai dali apenas IP, device, sessão e user-agent — o returnMessage e o returnCode são descartados. Para ter o motivo da recusa, use a ferramenta em Node da seção 4.
4. Análise profunda — a caixa de ferramentas em Node¶
A pasta tem uma segunda implementação desta mesma investigação, em Node.
Foi a primeira versão (19 a 24/08/2026), anterior à reescrita em Python, e
não foi aposentada: ela coleta 33 campos por pedido contra os 11 do
extrai-infra.py.
Executável equivalente:
8 - ANALISE PROFUNDA do periodo.bat
O que só o Node traz¶
| Campo | Por que importa |
|---|---|
motivo_pagamento (returnMessage) e codigo_retorno |
O motivo real da recusa. O extrai-infra.py chama a API de Pagamentos mas não extrai esses campos |
adquirente, status_adquirente |
Qual conector recusou e o que ele respondeu |
cpf, nome, telefone, cidade, uf |
Identificação do titular |
email desmascarado |
O Python devolve o e-mail com a máscara da VTEX (-123b.ct.vtex.com.br); o Node aplica emailReal() e limpa |
utm_source, utm_campaign |
De onde veio o pedido |
| correlação | Mesmo CPF / IP / device em outros pedidos, e quantos cartões distintos por CPF |
cd "C:\Projetos\vtex-analise"
node vtex_export_oms.mjs 2026-09-01 2026-09-30 # periodo escolhido
node vtex_export_oms.mjs # periodo padrao do topo do arquivo
node gerar_xlsx.mjs # monta Card_Testing_VTEX.xlsx
As datas são parâmetro desde 28/08/2026
Antes disso era preciso editar as constantes DE e ATE no topo do arquivo a cada investigação. Hoje elas continuam lá como padrão, usadas quando nenhuma data é passada — rodar sem argumento funciona igual a antes. As datas vão no formato AAAA-MM-DD; qualquer outro formato o script recusa antes de gastar chamada de API.
Qual usar: decida pelo custo de API¶
Esta é a razão de as duas existirem. O Node é mais completo, mas mais caro:
| Ferramenta | Chamadas por pedido | Campos | Quando usar |
|---|---|---|---|
vigia-dominios.py |
nenhuma (só lista) | — | Rotina semanal |
extrai-negados.py |
nenhuma (só lista) | Janela grande | |
extrai-infra.py |
2 | 11 | Janela média — IP, device e cartão |
vtex_export_oms.mjs |
3 + 240 ms de espera | 33 | Janela curta — investigação a fundo |
Não rode o Node em janela grande
Três chamadas por pedido mais a espera entre elas tornam a varredura de meses inteiros inviável. Para varrer, use o Python; para dissecar um período suspeito já identificado, use o Node.
Credenciais
Python e Node leem o mesmo .env da pasta — o env.mjs é quem faz a
ponte para os scripts em Node. O .gitignore bloqueia .env, CSVs e
planilhas.
5. Perfil de parcelamento (não é antifraude)¶
parcelas.mjs responde a uma pergunta comercial, não de segurança: em
quantas vezes o cliente real costuma dividir a compra, e em qual bandeira.
Olha só os meses limpos, sem ataque — incluir mês sujo contamina a média, porque pedido de bot é sempre à vista e de valor baixo.
cd "C:\Projetos\vtex-analise"
node parcelas.mjs # usa _2025.json desta pasta
node parcelas.mjs caminho\lista.json # usa outra exportação
Gera parcelas-2025.json com {mes, valor, parcelas, bandeira, valorParcela}.
O resultado da rodada de 21/08/2026 já está na pasta: 254 pedidos, nenhuma
falha.
Info
A entrada é a lista de pedidos gerada pelo _mensal2025.mjs, na mesma
pasta. Sem argumento, o script usa o _2025.json que já está lá.
6. Atualizar a planilha do panorama¶
A planilha card-testing-2024-2026.xlsx foi gerada com dados até 25/08/2026. Para atualizar com meses novos, rodar os três na ordem:
Executável equivalente:
9 - ATUALIZAR planilha do panorama.bat
python indice-pedidos.py 2024-01 2026-12 # índice de todos os pedidos
python extrai-infra.py 2026-09-01 2026-12-31 # detalhe dos negados novos
python monta-planilha.py # consolida
Feche a planilha no Excel antes do terceiro comando
Senão dá erro de permissão.
Warning
O monta-planilha.py lê todos os infra-*.csv da pasta e junta. Não apague os antigos.
Scripts da pasta¶
| Script | O que faz | Executável |
|---|---|---|
vigia-dominios.py |
Classifica domínios dos pedidos negados em JÁ COBERTO / PROVÁVEL REAL / INFRA NOVA | 2 |
mapa-mensal.py |
Taxa de recusa mês a mês | 3 |
extrai-infra.py |
Detalhe completo dos negados (IP, device, cartão) → infra-*.csv |
7 |
extrai-negados.py |
Só os e-mails dos negados — versão rápida | — |
indice-pedidos.py |
Índice de todos os pedidos do período → indice-pedidos.csv |
9 |
monta-planilha.py |
Consolida os infra-*.csv em card-testing-2024-2026.xlsx |
9 |
marca-cancelamento.py |
Marca cancelamentos → cancelamentos.csv |
— |
puxa-pedidos.py |
Coleta bruta de pedidos da API | — |
parcelas.mjs |
Perfil de parcelamento dos meses limpos → parcelas-2025.json |
— |
env.mjs |
Lê as credenciais do .env. Importado pelos scripts em Node |
— |
Scripts em Node (mesma pasta)¶
| Script | O que faz | Executável |
|---|---|---|
vtex_export_oms.mjs |
Coleta os 33 campos por pedido cruzando OMS + Payments + Transaction | 8 |
gerar_xlsx.mjs |
Monta Card_Testing_VTEX.xlsx a partir do vtex_dados.json |
8 |
_mensal2025.mjs |
Lista os pedidos de 2025 → _2025.json (entrada do parcelas.mjs) |
— |
_2026.mjs |
Mesma coisa para 2026 → _2026.json |
— |
Histórico¶
| Data | Evento |
|---|---|
| Julho/2026 | Início do ataque de card testing identificado na loja |
| 19/08/2026 | Chamado escalado na VTEX |
| 25/08/2026 | Validador de e-mail no ar; planilha de panorama 2024–2026 gerada |
| 28/08/2026 | Executáveis 7, 8 e 9 criados; vtex_export_oms.mjs passou a aceitar as datas por parâmetro |
| 28/08/2026 | saida/ reorganizada: uma pasta por script (antes eram 29 arquivos em saida/investigacao) |
Diagnóstico¶
| Sintoma | Causa provável e ação |
|---|---|
| Script retorna 401 / 403 | VTEX_APP_KEY ou VTEX_APP_TOKEN inválidos no .env. Regerar em VTEX Admin → Configurações da conta → Chaves de aplicação |
| Script retorna 429 | A VTEX pediu calma. Espere alguns minutos e rode de novo |
monta-planilha.py dá erro de permissão |
Planilha aberta no Excel. Fechar e rodar de novo |
| Planilha saiu com meses faltando | Algum infra-*.csv foi apagado da pasta. Rodar extrai-infra.py (ou o executável 7) para o período faltante |
extrai-infra.py demora demais |
Normal em janela grande — duas chamadas de API por pedido. Quebrar em períodos menores |
| Preciso do motivo da recusa e o CSV não tem | O extrai-infra.py não extrai esse campo. Use o executável 8 (vtex_export_oms.mjs) na janela específica |
E-mail no CSV vem com -123b.ct.vtex.com.br |
Máscara da VTEX. O Python não remove; o vtex_export_oms.mjs remove |
| Node muito lento ou estourando limite de API | Esperado: 3 chamadas por pedido, contra 2 do Python. Use o Python para janela grande |
.env nao encontrado ao rodar script Node |
O env.mjs procura o .env na pasta dele. Confirme que está rodando de dentro do vtex-analise |
Data inicial invalida no executável 8 |
A data precisa ser AAAA-MM-DD — 2026-09-01, não 01/09/2026 |
| Vigia não acha nada há semanas | Bom sinal: a blocklist está cobrindo. Confirmar com mapa-mensal.py que a taxa de recusa caiu |
| Taxa de recusa alta mas domínios são "PROVÁVEL REAL" | Não é card testing por e-mail descartável — investigar com o executável 7 (IP e device repetidos indicam bot; BINs variados indicam teste de cartão) |