
Script de shell para detectar indicadores do ataque à cadeia de suprimentos do npm da TanStack (CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx)
Detecta indicadores do ataque à cadeia de suprimentos do npm TanStack em uma máquina de desenvolvedor, um repositório ou um runner de CI. Script Bash, imagem Docker e GitHub Action — mesmo mecanismo, três pontos de entrada.
CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx
Em 11 de maio de 2026, atacantes publicaram 84 versões maliciosas em 42
pacotes @tanstack/* via envenenamento de cache do GitHub Actions. O payload
rouba tokens do GitHub, tokens npm, credenciais AWS/GCP/Azure e instala um
daemon dead-man's switch que apaga ~/ no momento em que o token roubado
é revogado.
Escolha o ponto de entrada que corresponde aonde você está.
TAG=v1.0.0
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh.sha256
sha256sum -c check.sh.sha256
bash check.sh --online
docker run --rm -v "$PWD":/scan \
ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
/scan true fail tanstack-findings.json '' GHSA-g7cv-rxg3-hmpx
A imagem é multi-arquitetura (linux/amd64, linux/arm64) e vem com
proveniência de build assinada via GitHub OIDC. Verifique antes de executar:
gh attestation verify \
oci://ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
--repo fabriziosalmi/tanstack-compromise-checker
permissions: {}
jobs:
check:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: fabriziosalmi/tanstack-compromise-checker@v1
with:
scan-dir: .
online: 'true'
fail-on: fail
Um workflow completo e endurecido está em
.github/workflows/tanstack-check.yml
e é o mesmo workflow que este repositório executa contra si mesmo.
Com --online, o script também busca o advisory do GHSA em tempo de execução
para que a cobertura de detecção acompanhe o estado mais recente do advisory em
vez de uma lista embutida de versões.
Família afetada: @tanstack/router, @tanstack/react-router,
@tanstack/history, @tanstack/start, @tanstack/eslint-plugin-router e
pacotes relacionados.
Famílias limpas (não afetadas): @tanstack/react-query,
@tanstack/react-table, @tanstack/react-virtual, @tanstack/form,
@tanstack/store.
# Quick check (current user's home)
bash check.sh
# Online mode: query the GHSA advisory and npm registry publish-time
bash check.sh --online
# Scan a specific directory
bash check.sh --scan-dir /path/to/your/repos
# JSON output for CI/SIEM integration
bash check.sh --json > findings.json
# Suggest pin commands for affected repos (dry-run)
bash check.sh --scan-dir /path/to/repos --fix
# Provide an extended known-bad list
bash check.sh --bad-versions-file ./extra-bad-versions.txt
| Código | Significado |
|---|---|
| 0 | Limpo — nenhum indicador no escopo verificado |
| 1 | Apenas avisos — revisão recomendada |
| 2 | Falhas — indicadores de comprometimento presentes |
| 3 | Erro de ferramenta/uso |
Este repositório se defende contra a mesma classe de ataque que detecta. Concretamente:
uses: de GitHub Action está fixado em um SHA de commit de 40 caracteres, não em uma tag flutuante.permissions: {} no nível superior; os jobs concedem apenas o que precisam.actions/checkout é invocado com persist-credentials: false para que nenhum remote git autenticado seja deixado em $GITHUB_WORKSPACE.step-security/harden-runner é o primeiro passo de cada workflow e monitora o tráfego de saída do runner.main; os resultados são enviados como SARIF.gh attestation.check.sh.sha256 que cobre todos os artefatos instaláveis.A política completa está em SECURITY.md.
Não use curl | bash para nenhuma ferramenta de segurança, incluindo esta. Sempre baixe, verifique o checksum, inspecione e então execute.
━━ 1 / 8 DEAD-MAN'S SWITCH ARTEFACTS
✔ No dead-man's switch artefacts found
━━ 2 / 8 PERSISTENCE VECTORS
✔ No persistence vectors detected
━━ 3 / 8 TOKEN / CREDENTIAL EXPOSURE
✔ No credential exposure detected
━━ 4 / 8 NETWORK INDICATORS
✔ No node TCP connections currently established (or none observable)
━━ 5 / 8 REPO SCAN — package.json + lockfiles
ℹ Found 12 package.json + 8 lockfile(s)
✔ No compromised family declared in any package.json
✔ No compromised pins found in any lockfile
━━ 6 / 8 INSTALLED node_modules — direct version check
✔ No compromised packages in installed node_modules
━━ 7 / 8 GITHUB ACTIONS HARDENING HINTS
✔ No risky GitHub Actions patterns detected (in scanned scope)
━━ 8 / 8 MINI SHAI-HULUD PAYLOAD + AUXILIARY IOCs
✔ No Mini Shai-Hulud payload / auxiliary IOCs detected
━━ SUMMARY
Passed: 8 Warnings: 0 Failed: 0
Scope : /Users/alice/dev
✔ No indicators of compromise within scope: /Users/alice/dev
Note: a clean result for /Users/alice/dev does not certify the rest of the system.
NÃO revogue seu token do GitHub antes de parar o daemon — o dead-man's switch executará
rm -rf ~/no momento em que o token for revogado.
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.user.gh-token-monitor.plistlaunchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plistsystemctl --user stop gh-token-monitor && systemctl --user disable gh-token-monitorrm -f ~/.local/bin/gh-token-monitor.sh~/.aws/credentials, ~/.kube/config, ~/.config/gh/hosts.yml,
~/.npmrc.O script bash precisa de:
bash 4+jq (recomendado) — análise de package-lock.jsonpython3 (fallback opcional) — usado quando jq está ausentecurl — exigido para --onlinelsof ou ss (opcional) — heurística de IOC de redeA imagem Docker inclui tudo isso. Use-a em sistemas onde você não pode ou não quer instalar essas ferramentas.
Issues e pull requests são bem-vindos. Observe que este repositório usa CODEOWNERS: todos os PRs exigem revisão de um mantenedor.
MIT.
| # | Verificação | Descrição |
|---|
| 1 | Dead-man's switch | ~/.local/bin/gh-token-monitor.sh, LaunchAgents + LaunchDaemons (macOS), unidades systemd de usuário + sistema (Linux), processos em execução |
| 2 | Persistência | arquivos rc do shell, crontab de usuário/sistema, /etc/cron.*, autostart XDG, core.hooksPath global do git |
| 3 | Credenciais | variáveis de ambiente sensíveis, ~/.npmrc, ~/.yarnrc.yml, ~/.aws/credentials, ~/.config/gh/hosts.yml, ~/.netrc, ~/.docker/config.json, ~/.kube/config, enumeração de arquivos .env* |
| 4 | IOC de rede | processos node em execução com conexões TCP de saída estabelecidas (heurística, revisão manual) |
| 5 | Varredura de repositório | dependências declaradas em package.json + versões fixadas em lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) |
| 6 | Instalados | node_modules/@tanstack/*/package.json verificado contra a lista de versões maliciosas conhecidas e depois contra o time[<version>] do registro npm quando --online |
| 7 | Dicas de Actions | .github/workflows/* varridos em busca de pull_request_target, ausência de --ignore-scripts, uso de actions/cache |
| 8 | IOCs Mini Shai-Hulud | arquivos de payload em node_modules (router_init.js, tanstack_runner.js), dependência opcional @tanstack/setup, adulteração de configuração de ferramentas de IA, domínios C2 no código-fonte, padrões de autor de commit + branch do atacante, tokens npm marcados para resgate, pacotes secundários propagados por worm, além de heurísticas de nível informativo para formatos de payload desconhecidos |
| Flag | Descrição |
|---|
--scan-dir DIR | Diretório raiz a ser verificado (padrão: $HOME). Recusa verificar diretórios de sistema como /, /etc, /usr. |
--online | Consulta o advisory do GHSA e o time[<version>] do registro npm para confirmar o comprometimento. Desativado por padrão — opt-in. |
--ghsa GHSA-ID | Substitui o ID do advisory usado em --online (padrão GHSA-g7cv-rxg3-hmpx). |
--attack-window-start ISO, --attack-window-end ISO | Substitui a janela de tempo de publicação usada em --online. |
--fix | Exibe comandos de fixação recomendados para repositórios afetados (dry-run por padrão). |
--apply | Com --fix: opt-in para execução. Atualmente ainda recusa update cego; é necessária fixação manual. |
--yes, -y | Pula o prompt de confirmação para --apply. |
--json | Emite descobertas como JSON para stdout (implica --quiet). |
--bad-versions-file F | Acrescenta entradas (pkg@version, uma por linha) à lista de versões maliciosas conhecidas. |
--no-color | Desativa cores ANSI. |
--quiet, -q | Suprime a saída por verificação, exibe apenas o resumo. |
-h, --help | Mostra ajuda. |