Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
npm-incident-response — Scanner para o ataque à cadeia de suprimentos keyv/cacheable: detecta pacotes npm comprometidos, verifica hashes de payload e encontra implantes de persistência nos modos repo e host. | Kitploit
Ferramentas/GitHubGitHub/securest8/npm-incident-response
Scanners de VulnerabilidadesMecanismos de PersistênciaAnálise de MalwareForensia DigitalSegurança da Cadeia de SuprimentosResposta a Incidentes
GitHubsecurest8/npm-incident-response

npm-incident-response

Scanner para o ataque à cadeia de suprimentos keyv/cacheable: detecta pacotes npm comprometidos, verifica hashes de payload e encontra implantes de persistência nos modos repo e host.

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Ver Repositório
21há 14 diasAinda não revisado

npm-incident-response

English | Português

Scanner standalone para o incidente de supply chain keyv/cacheable ("Shai-Hulud: Here We Go Again", 04/ago/2026) — 440+ pacotes npm comprometidos por um worm auto-propagante que rouba credenciais de cloud/CI e planta persistência com dead-man's switch.

O output do scanner é em inglês (findings, ações, relatório HTML). Esta página traduz o contexto e o passo a passo para o público brasileiro; os comandos são idênticos aos da versão em inglês.

Detecta, em minutos e sem instalar nada:

  • Pacotes comprometidos em package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 e Berry), pnpm-lock.yaml e bun.lock — incluindo dependências transitivas, com a cadeia completa (ex.: eslint → file-entry-cache → flat-cache → [email protected]);
  • Payloads instalados em node_modules (nome + hash SHA-256 dos artefatos conhecidos);
  • Variantes ainda fora das listas de IOC (heurística: lifecycle scripts suspeitos, arquivos com nomes do worm) — sempre marcadas como SUSPECT, nunca confirmadas sem hash;
  • Implantes de persistência no host: LaunchAgent (macOS), serviço systemd de usuário + linger (Linux), hooks em .claude/settings.json e .vscode/tasks.json, artefatos temporários (bun-dl-*);
  • O dead-man's switch: o implante monitora um token GitHub e executa um comando remoto quando a revogação retorna 4xx. Rotacionar credenciais antes de limpar o host detona a armadilha — o relatório avisa, e a ordem de resposta abaixo evita o erro.

Entenda o ataque

  1. A conta do mantenedor das famílias keyv/cacheable foi comprometida; o atacante publicou versões novas com um gancho "preinstall": "node setup.mjs" — código que roda antes de o pacote ser instalado, com os privilégios de quem rodou npm install.
  2. setup.mjs baixa o runtime Bun do GitHub e executa o payload nele — evasão contra ferramentas que só monitoram processos node.
  3. Math_Symbol.js (~728 KB, ofuscado) rouba credenciais: metadados de instância AWS, chaves AWS/GCP/Azure, tokens Vault, service accounts de Kubernetes, secrets de GitHub Actions, tokens npm, e faz varredura genérica por regex atrás de chaves privadas e bearer tokens em disco.
  4. É um worm: com o token npm roubado, injeta o mesmo gancho em outros pacotes que aquela identidade publica, recalcula os hashes de integridade e republica. Foi assim que saiu de ~10 para centenas de pacotes.
  5. Exfiltra sem C2 fixo (repositórios GitHub criados na hora, DNS) e deixa uma armadilha para trás — ver abaixo.

Os dois vetores (o segundo é mais sutil)

  • Vetor A — instalação: quem rodou npm install/npm ci com lifecycle scripts habilitados desde 04/08/2026 09:35 UTC. Com --ignore-scripts, o gancho não executou.
  • Vetor B — clone: o repositório fonte recebeu hooks de autostart em .claude/settings.json (SessionStart) e .vscode/tasks.json (folderOpen) que executam o loader ao abrir a pasta clonada — sem npm install, sem instalar nada. Isso inclui quem clonou o repositório para investigar o incidente e agentes de codificação com IA que abriram o diretório — um dos primeiros casos públicos de hooks de agente de IA (.claude/) usados como vetor de supply chain.

A armadilha (dead-man's switch)

O implante instala um "vigia" (gh-token-monitor) mantido vivo por LaunchAgent (macOS) ou serviço systemd de usuário + loginctl enable-linger (Linux). A cada 60 segundos ele valida o token GitHub roubado contra a API. Enquanto o token funciona, nada acontece. Quando a resposta vira 4xx — ou seja, no instante em que você revoga o token — ele executa via eval o conteúdo de ~/.config/gh-token-monitor/handler: um comando arbitrário definido remotamente pelo atacante. A análise pública não sabe o que ele contém — pode ser destruição de dados, reimplante, ransomware ou nada. O risco não é avaliável; por isso a ordem de resposta é absoluta.

Três propriedades que mudam a resposta:

  • Isolar a rede é seguro: sem conectividade não existe resposta HTTP, logo não existe 4xx — a armadilha não dispara, e a exfiltração para. Isole primeiro, não desligue (memória volátil é evidência).
  • É de tiro único e se limpa sozinha após disparar — o comportamento fica inexplicável, sem artefato para investigar.
  • TTL de ~24h: o vigia se autodestrói sozinho depois de um dia. Ausência de artefatos não prova que a máquina esteve limpa — o scanner avisa isso no modo host.

Por que as defesas usuais geralmente não pegam

  • "A assinatura estava válida" — [email protected] saiu com atestação SLSA passando. Provenance atesta integridade de build, não de fonte: o workflow legítimo compilou código já trojanizado.
  • "O diff do código não mudou" — correto: a biblioteca em si não foi alterada. A malícia está no package.json (o gancho preinstall) e em dois arquivos novos adicionados ao pacote (setup.mjs, Math_Symbol.js).
  • "Não usamos keyv" — usam, indiretamente: a cadeia mais comum é eslint → file-entry-cache → flat-cache → keyv. Por isso o scanner mostra a cadeia em cada achado.
  • "Ninguém rodou npm install" — insuficiente: ver Vetor B.

O que é o script fornecido neste repositório

O scan.mjs tem as seguintes características — importantes para quem está respondendo a um incidente de supply chain:

  • Um único arquivo, ~880 linhas legíveis, zero dependências. Nada de npm install. Audite scan.mjs inteiro em 15 minutos antes de rodar.
  • Zero egress. Nenhum dado sai da sua máquina. Não há telemetria, não há "envie o resultado para análise". A única operação de rede é --update (baixar manifesto de IOCs novo), explícita e opcional.
  • Somente leitura. O scanner não altera, não remove e não executa nada do que encontra.
  • Funciona offline. docker run --network=none ou máquina isolada: basta copiar scan.mjs + iocs.json.

Como usar na sua empresa

Requisito: Node.js ≥ 18 (qualquer máquina com npm já tem). Baixe os dois arquivos — scan.mjs + iocs.json — e pronto: não há instalação.

Heads-up: se você clonou este repositório inteiro, a pasta fixtures/ contém IOCs inertes usados nos testes (nomes e versões reais, conteúdo dummy — não há malware). O scanner a ignora automaticamente e avisa no output; achados vindos dela só aparecem se você a escanear de propósito.

Há dois modos de execução que respondem perguntas diferentes e é isso que define onde rodar:

  • O modo repo lê lockfiles e node_modules — e lockfiles estão no git, então pode ser centralizado: uma pessoa varre todos os repositórios da empresa.
  • O modo host procura o implante (watcher, LaunchAgent/systemd, hooks de IDE), que mora na máquina onde o código executou — isso não está no git e não dá para centralizar.

Passo 1 — AppSec varre todos os repositórios (uma pessoa, uma máquina)

root@kitploit:~
node scan.mjs repo /pasta/com/todos/os/repositorios --json=resultado.json --html=relatorio.html

Responde "quais projetos estão expostos" em minutos, sem envolver ninguém. Aceita vários caminhos; varre subdiretórios (monorepos e workspaces inclusos).

Passo 2 — quem trabalhou nos projetos atingidos escaneia a própria máquina

Para cada projeto com achado, identifique quem mexeu nele desde 04/08 09:35 UTC (git log, logs de CI). Essas pessoas rodam, na máquina delas:

root@kitploit:~
node scan.mjs        # diretório atual + host, em ~30 segundos

Está no escopo quem: (a) rodou npm install/npm ci na janela; ou (b) apenas clonou e abriu a pasta no VS Code ou num agente de IA — o vetor B dispensa instalação.

Como o custo é ~30 segundos e o funil pode vazar (clone avulso, projeto pessoal), o comunicado interno mais seguro é: todo desenvolvedor roda node scan.mjs uma vez e envia o --json/--html ao AppSec. O envio é manual por princípio — o scanner não tem telemetria (zero egress).

Passo 3 — runners de CI e servidores de build

Prioridade máxima: é onde moram as credenciais mais valiosas. Aqui o scanner tem dois papéis diferentes — um para o passado, outro para o futuro:

Triagem do passado — NÃO escaneie o runner para decidir. A pergunta "este runner foi atingido?" não se responde com scan: se algum job instalou versão afetada sem --ignore-scripts desde 04/08, as credenciais já foram roubadas naquele momento, e o host do runner raramente guarda evidência (runners efêmeros destroem o container ao fim do job; o watcher se apaga em ~24h). Quem responde são os lockfiles do Passo 1 e os logs de CI. Se a resposta for "sim, instalou": recrie o runner e rotacione os secrets dele — runners são efêmeros, não há justificativa para limpá-los.

Prevenção daqui para frente — SIM, rode no pipeline. Adicione o scanner como etapa do build, em modo repo, depois do checkout e antes do npm install. Ele não examina o host do runner — examina o código que vai ser instalado, e o exit code quebra o build antes de o preinstall malicioso ter chance de rodar:

root@kitploit:~
# exemplo (GitHub Actions / GitLab CI — adapte):
- run: node scan.mjs repo . --json    # exit 0 limpo · 1 achados · 2 COMPROMISED
- run: npm ci --ignore-scripts        # só executa se o passo anterior passou

Referência rápida

root@kitploit:~
node scan.mjs                     # varre o diretório atual + o host
node scan.mjs repo /caminho/a /caminho/b
node scan.mjs host                # só persistência/implantes na máquina
node scan.mjs repo . --json=resultado.json --html=relatorio.html
node scan.mjs --update            # atualiza iocs.json (única operação com rede)

Triagem

Relatório como evidência

--html gera um relatório autocontido com timestamp, hostname, versão do manifesto de IOCs e SHA-256 do próprio scanner — serve como anexo de notificação de incidente e trilha de auditoria.

Se o scanner acusou COMPROMISED: a ordem de resposta

Não revogue nem rotacione nenhuma credencial ainda — é o gatilho da armadilha. A sequência:

1. ISOLAR — corte a rede da máquina. É seguro: sem resposta HTTP não há 4xx, a armadilha não dispara, e a exfiltração para. Não desligue (memória volátil é evidência).

2. PRESERVAR — antes de apagar qualquer coisa (o vigia se autodestrói em ~24h):

root@kitploit:~
mkdir -p /tmp/evidencia && cp -r ~/.config/gh-token-monitor /tmp/evidencia/ 2>/dev/null
cp /tmp/gh-token-monitor.*.log /tmp/evidencia/ 2>/dev/null
shasum -a 256 /tmp/evidencia/* 2>/dev/null

O arquivo handler é o comando do atacante que seria executado — não execute, não cole em um shell; trate como texto inerte. O started_at delimita a janela de exposição (o auditor e o regulador vão pedir).

3. ERRADICAR — mate o processo do watcher primeiro, depois:

root@kitploit:~
# macOS
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm -f ~/Library/LaunchAgents/com.user.gh-token-monitor.plist

# Linux
systemctl --user disable --now gh-token-monitor.service
loginctl disable-linger "$USER"
rm -f ~/.config/systemd/user/gh-token-monitor.service

# ambos
rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh /tmp/bun-dl-*

Remova também os hooks maliciosos de .claude/settings.json e .vscode/tasks.json, os arquivos setup.mjs/Math_Symbol.js/math_init.js e limpe os caches (~/.npm/_cacache, pnpm, yarn). Rode node scan.mjs host de novo até zerar.

4. ROTACIONAR — só com todos os hosts limpos e verificados (basta um vigia vivo para o gatilho disparar). Revogue o token npm primeiro (interrompe a propagação do worm); depois GitHub (PATs, deploy keys), AWS/GCP/Azure, Vault, Kubernetes, secrets de CI — e qualquer segredo que estava em disco, porque houve varredura por regex.

5. AUDITAR — o worm age em seu nome: procure repositórios com a descrição Shai-Hulud: Here We Go Again nas suas organizações, versões npm publicadas inesperadamente desde 04/08 (deprecie e avise os consumidores), e uso das credenciais no CloudTrail/Audit Logs dentro da janela do started_at.

Depois: apague node_modules, reinstale de lockfile íntegro com --ignore-scripts. Runners de CI e hosts com execução confirmada: reconstruir do zero, sempre — houve execução de código arbitrário e a lista de artefatos conhecidos não é garantia de completude.

Instituições reguladas (BR): comprometimento confirmado com acesso a credenciais pode acionar obrigações de comunicação (Res. CMN 4.893/2021, Res. BCB 85/2021; LGPD art. 48 se houver dados pessoais). Documente a linha do tempo em UTC — started_at, detecção, contenção, erradicação, rotação — e confirme prazos com jurídico/compliance.

Atualizando os IOCs (usuários)

O incidente está ativo e a lista cresce. Para puxar o manifesto mais recente:

root@kitploit:~
node scan.mjs --update          # única operação com acesso à rede

O --update busca o iocs.json deste repositório (securest8/npm-incident-response), nunca de terceiros — a Securest8 é o portão de curadoria. Você recebe o que foi publicado aqui por último.

Mantendo os IOCs (mantenedores)

A lista de pacotes vem do feed público da Wiz; os hashes, domínios C2, IOCs de persistência e versões seguras são estáticos e curados em tools/gen-iocs.mjs. Um snapshot do CSV da Wiz fica em tools/keyv-packages.csv para reprodutibilidade e execução offline.

root@kitploit:~
node tools/gen-iocs.mjs               # busca o CSV da Wiz, regenera o iocs.json + atualiza o snapshot
node tools/gen-iocs.mjs --offline     # regenera do snapshot commitado, sem rede
node tools/gen-iocs.mjs --allow-shrink # permite contagem menor que a do snapshot (guarda ativa por padrão)

O gerador é idempotente: mantém o manifest_version atual e não reescreve o arquivo quando nada material mudou, e se recusa a escrever um manifesto vazio ou menor (proteção contra um feed truncado/alterado a montante).

Automação: .github/workflows/update-iocs.yml roda o gerador diariamente (e sob demanda) e commita na main só quando os IOCs de fato mudam — assim o --update dos usuários acompanha o feed da Wiz com ~1 dia de atraso, com o histórico auditável nos commits. Troque para um passo de pull request (indicado no workflow) quando o incidente esfriar e você preferir merge manual.

Testes

root@kitploit:~
node test/run-tests.mjs         # 15 asserções contra fixtures/demo-repo

fixtures/demo-repo é um repositório de teste com IOCs inertes (nomes e versões reais, conteúdo dummy — não contém malware). Ao varrer o repositório do scanner, a pasta fixtures/ é ignorada automaticamente (com aviso no output); os testes a escaneiam passando o caminho explicitamente.

Escopo e crédito

Ferramenta de incidente único, feita para triagem rápida durante a janela ativa do ataque — não substitui Socket, Snyk ou similares. Pesquisa e IOCs: Socket.dev, Wiz Research (CSV público), Kodem Security.

Mantido por Securest8. Licença MIT.

Baixar ferramenta
NívelSignificadoAção
COMPROMISEDVersão maliciosa instalada em node_modules, payload confirmado por hash, ou implante de persistência encontradoTratar o host como comprometido; seguir a ordem de resposta — limpar implante antes de rotacionar credenciais
EXPOSEDVersão maliciosa pinada em lockfile, sem evidência de execuçãoFixar versão segura, apagar node_modules, reinstalar com --ignore-scripts
AT_RISKRange (^/~) no package.json que admite versão maliciosaFixar versão exata ou bloquear no proxy de registro
SUSPECTHeurística (nome de arquivo do worm com hash divergente, lifecycle script suspeito)Inspecionar manualmente — pode ser variante nova ou falso positivo
INFOVetor presente mas sem IOC (ex.: task folderOpen genérica)Revisar