
Script shell pour détecter les indicateurs d'attaque de la chaîne d'approvisionnement npm TanStack (CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx)
Détectez les indicateurs de l'attaque sur la chaîne d'approvisionnement npm de TanStack sur une machine de développeur, un dépôt ou un runner CI. Script Bash, image Docker et action GitHub — même moteur, trois points d'entrée.
CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx
Le 11 mai 2026, des attaquants ont publié 84 versions malveillantes dans 42 paquets @tanstack/* via un empoisonnement du cache des actions GitHub. La charge utile vole les jetons GitHub, les jetons npm, les identifiants AWS/GCP/Azure, et installe un démon de commutateur à action différée (dead-man's switch) qui efface ~/ dès que le jeton volé est révoqué.
Choisissez le point d'entrée qui correspond à votre environnement.
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
L'image est multi-architecture (linux/amd64, linux/arm64) et est livrée avec une provenance de construction signée via GitHub OIDC. Vérifiez avant d'exécuter :
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
Un workflow complet durci se trouve dans
.github/workflows/tanstack-check.yml
et c'est le même workflow que ce dépôt utilise contre lui-même.
| # | Vérification | Description |
|---|---|---|
| 1 | Commutateur à action différée | ~/.local/bin/gh-token-monitor.sh, LaunchAgents + LaunchDaemons (macOS), unités systemd utilisateur + système (Linux), processus en cours d'exécution |
| 2 | Persistance | fichiers rc du shell, crontab utilisateur/système, /etc/cron.*, démarrage automatique XDG, core.hooksPath git global |
| 3 | Identifiants | variables d'environnement sensibles, ~/.npmrc, ~/.yarnrc.yml, ~/.aws/credentials, ~/.config/gh/hosts.yml, ~/.netrc, ~/.docker/config.json, ~/.kube/config, énumération des fichiers .env* |
| 4 | IOC réseau | processus node en cours d'exécution avec des connexions TCP sortantes établies (heuristique, vérification manuelle) |
| 5 | Analyse du dépôt | dépendances déclarées dans package.json + versions épinglées dans le fichier de verrouillage (package-lock.json, yarn.lock, pnpm-lock.yaml) |
| 6 | Installé | node_modules/@tanstack/*/package.json vérifié par rapport à la liste des versions malveillantes connues, puis par rapport au registre npm time[<version>] avec --online |
| 7 | Indices Actions | .github/workflows/* scanné pour pull_request_target, --ignore-scripts manquant, utilisation de actions/cache |
| 8 | IOC Mini Shai-Hulud | fichiers de charge utile dans node_modules (router_init.js, tanstack_runner.js), dépendance optionnelle @tanstack/setup, falsification de configuration d'outil IA, domaines C2 dans le code source, auteur de commit malveillant + motifs de branche, jetons npm marqués pour rançon, paquets secondaires propagés par ver, plus heuristiques de niveau information pour les formes de charge utile inconnues |
Avec --online, le script récupère également l'avis GHSA au moment de l'exécution afin que la couverture de détection suive l'état en direct de l'avis au lieu d'une liste codée en dur de versions.
Famille affectée : @tanstack/router, @tanstack/react-router,
@tanstack/history, @tanstack/start, @tanstack/eslint-plugin-router et paquets associés.
Familles propres (non affectées) : @tanstack/react-query,
@tanstack/react-table, @tanstack/react-virtual, @tanstack/form,
@tanstack/store.
# Vérification rapide (répertoire personnel de l'utilisateur actuel)
bash check.sh
# Mode en ligne : interroger l'avis GHSA et l'heure de publication du registre npm
bash check.sh --online
# Scanner un répertoire spécifique
bash check.sh --scan-dir /chemin/vers/vos/depots
# Sortie JSON pour intégration CI/SIEM
bash check.sh --json > findings.json
# Suggérer des commandes d'épinglage pour les dépôts affectés (essai à blanc)
bash check.sh --scan-dir /chemin/vers/depots --fix
# Fournir une liste étendue de versions malveillantes connues
bash check.sh --bad-versions-file ./extra-bad-versions.txt
| Option | Description |
|---|---|
--scan-dir REPERTOIRE | Répertoire racine à scanner (par défaut : $HOME). Refuse de scanner les répertoires système comme /, /etc, /usr. |
--online | Interroger l'avis GHSA et le time[<version>] du registre npm pour confirmer la compromission. Désactivé par défaut — activable. |
--ghsa ID-GHSA | Surcharger l'identifiant d'avis utilisé avec --online (par défaut GHSA-g7cv-rxg3-hmpx). |
--attack-window-start ISO, --attack-window-end ISO | Surcharger la fenêtre de publication utilisée avec --online. |
--fix | Afficher les commandes d'épinglage recommandées pour les dépôts affectés (essai à blanc par défaut). |
--apply | Avec --fix : activer l'exécution. Actuellement, refuse encore les update aveugles ; l'épinglage manuel est requis. |
--yes, -y | Ignorer l'invite de confirmation pour --apply. |
--json | Émettre les résultats au format JSON sur stdout (implique --quiet). |
--bad-versions-file FICHIER | Ajouter des entrées (paquet@version, une par ligne) à la liste des versions malveillantes connues. |
--no-color | Désactiver les couleurs ANSI. |
--quiet, -q | Supprimer la sortie par vérification, n'afficher que le résumé. |
-h, --help | Afficher l'aide. |
| Code | Signification |
|---|---|
| 0 | Propre — aucun indicateur dans le périmètre scanné |
| 1 | Avertissements uniquement — révision recommandée |
| 2 | Échecs — indicateurs de compromission présents |
| 3 | Erreur d'outil/d'utilisation |
Ce dépôt se défend contre la même classe d'attaque qu'il détecte. Concrètement :
uses: d'action GitHub est épinglé à un SHA de commit de 40 caractères, pas à un tag flottant.permissions: {} au niveau supérieur ; les jobs n'accordent que ce dont ils ont besoin.actions/checkout est invoquée avec persist-credentials: false afin qu'aucun dépôt git authentifié ne soit laissé dans $GITHUB_WORKSPACE.step-security/harden-runner est la première étape de chaque workflow et surveille le trafic sortant du runner.main ; les résultats sont téléchargés au format SARIF.gh attestation.check.sh.sha256 couvrant tous les artefacts installables.La politique complète se trouve dans SECURITY.md.
Ne pipez pas curl | bash pour un outil de sécurité, y compris celui-ci. Téléchargez toujours, vérifiez la somme de contrôle, inspectez, puis exécutez.
━━ 1 / 8 ARTÉFACTS DU COMMUTATEUR À ACTION DIFFÉRÉE
✔ Aucun artéfact de commutateur à action différée trouvé
━━ 2 / 8 VECTEURS DE PERSISTANCE
✔ Aucun vecteur de persistance détecté
━━ 3 / 8 EXPOSITION DE JETONS / IDENTIFIANTS
✔ Aucune exposition d'identifiant détectée
━━ 4 / 8 INDICATEURS RÉSEAU
✔ Aucune connexion TCP node actuellement établie (ou observable)
━━ 5 / 8 ANALYSE DU DÉPÔT — package.json + verrous
ℹ 12 fichiers package.json + 8 fichier(s) de verrou trouvés
✔ Aucune famille compromise déclarée dans les package.json
✔ Aucun épinglage compromis trouvé dans les fichiers de verrou
━━ 6 / 8 node_modules INSTALLÉS — vérification directe des versions
✔ Aucun paquet compromis dans les node_modules installés
━━ 7 / 8 INDICES DE DURCISSEMENT DES ACTIONS GITHUB
✔ Aucun motif risqué d'actions GitHub détecté (dans le périmètre scanné)
━━ 8 / 8 CHARGE UTILE MINI SHAI-HULUD + IOC AUXILIAIRES
✔ Aucune charge utile / IOC auxiliaire Mini Shai-Hulud détecté
━━ RÉSUMÉ
Réussis : 8 Avertissements : 0 Échecs : 0
Périmètre : /Users/alice/dev
✔ Aucun indicateur de compromission dans le périmètre : /Users/alice/dev
Remarque : un résultat propre pour /Users/alice/dev ne certifie pas le reste du système.
NE révoquez PAS votre jeton GitHub avant d'arrêter le démon — le commutateur à action différée exécutera
rm -rf ~/dès que le jeton sera révoqué.
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.Le script Bash nécessite :
bash 4+jq (recommandé) — analyse de package-lock.jsonpython3 (solution de secours optionnelle) — utilisé en l'absence de jqcurl — requis pour --onlinelsof ou ss (optionnel) — heuristique IOC réseauL'image Docker intègre tous les éléments ci-dessus. Utilisez-la sur les systèmes où vous ne pouvez pas ou ne voulez pas installer ces outils.
Les demandes d'ajout et les pull requests sont les bienvenues. Notez que ce dépôt utilise CODEOWNERS : toutes les PR nécessitent une revue par un mainteneur.
MIT.