Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
npm-incident-response — Scanner pour l'attaque de la chaîne d'approvisionnement keyv/cacheable : détecte les paquets npm compromis, vérifie les hashs des payloads et recherche les implants de persistance en modes repo et hôte. | Kitploit
Outils/GitHubGitHub/securest8/npm-incident-response
Scanners de VulnérabilitésMécanismes de PersistanceAnalyse de MalwareCriminalistique NumériqueSécurité de la Chaîne LogistiqueRéponse aux Incidents
GitHubsecurest8/npm-incident-response

npm-incident-response

Scanner pour l'attaque de la chaîne d'approvisionnement keyv/cacheable : détecte les paquets npm compromis, vérifie les hashs des payloads et recherche les implants de persistance en modes repo et hôte.

Voir le dépôt
215il y a 1 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

npm-incident-response

English | Português

Scanner autonome pour l'incident de chaîne d'approvisionnement keyv/cacheable (« Shai-Hulud: Here We Go Again », 4 août 2026) — plus de 440 paquets npm compromis par un ver auto-propagateur qui vole des identifiants cloud/CI et installe une persistance avec un interrupteur homme mort.

Détecte, en quelques minutes et sans rien installer :

  • Paquets compromis dans package-lock.json, npm-shrinkwrap.json, yarn.lock (v1 et Berry), pnpm-lock.yaml et bun.lock — y compris les dépendances transitives, avec la chaîne complète (p. ex. eslint → file-entry-cache → flat-cache → [email protected]) ;
  • Charges utiles installées (payloads) dans node_modules (nom + empreinte SHA-256 des artefacts connus) ;
  • Variantes pas encore dans les listes d'IOC (heuristique : scripts de cycle de vie suspects, fichiers portant les noms du ver) — toujours marquées SUSPECT, jamais confirmées sans empreinte ;
  • Implants de persistance hôte : LaunchAgent (macOS), service utilisateur systemd + linger (Linux), hooks dans .claude/settings.json et .vscode/tasks.json, artefacts temporaires (bun-dl-*) ;
  • L'interrupteur homme mort (dead-man's switch) : l'implant surveille un jeton GitHub et exécute une commande distante lorsque la révocation renvoie une 4xx. Faire pivoter les identifiants avant de nettoyer l'hôte déclenche le piège — le rapport vous en avertit, et l'ordre de réponse ci-dessous évite l'erreur.
  • Comprendre l'attaque

    1. Le compte mainteneur des familles keyv/cacheable a été compromis ; l'attaquant a publié de nouvelles versions avec un hook "preinstall": "node setup.mjs" — du code qui s'exécute avant l'installation du paquet, avec les privilèges de celui qui a lancé npm install.
    2. setup.mjs télécharge le runtime Bun depuis GitHub et y exécute la charge utile — une évasion face aux outils qui ne surveillent que les processus node.
    3. Math_Symbol.js (~728 Ko, obfusqué) vole des identifiants : métadonnées d'instance AWS, clés AWS/GCP/Azure, jetons Vault, comptes de service Kubernetes, secrets GitHub Actions, jetons npm, plus un balayage regex générique à la recherche de clés privées et de jetons bearer sur le disque.
    4. C'est un ver : avec le jeton npm volé, il injecte le même hook dans d'autres paquets que cette identité peut publier, recalcule les empreintes d'intégrité et republie. C'est ainsi qu'il est passé d'environ 10 à des centaines de paquets.
    5. Il exfiltre sans C2 fixe (dépôts GitHub créés à la volée, DNS) et laisse un piège derrière lui — voir ci-dessous.

    Les deux vecteurs (le second est plus subtil)

    • Vecteur A — installation : toute personne ayant exécuté npm install/npm ci avec les scripts de cycle de vie activés depuis 2026-08-04 09:35 UTC. Avec --ignore-scripts, le hook ne s'exécutait pas.
    • Vecteur B — clonage : le dépôt source a reçu des hooks de démarrage automatique dans .claude/settings.json (SessionStart) et .vscode/tasks.json (folderOpen) qui exécutent le chargeur à l'ouverture du dossier cloné — pas de npm install, rien d'installé. Cela inclut les personnes ayant cloné le dépôt pour enquêter sur l'incident et les agents de codage IA ayant ouvert le répertoire — l'un des premiers cas publics de hooks d'agents IA (.claude/) utilisés comme vecteur de chaîne d'approvisionnement.

    Le piège (interrupteur homme mort)

    L'implant installe un « watcher » (gh-token-monitor) maintenu en vie par un LaunchAgent (macOS) ou un service utilisateur systemd + loginctl enable-linger (Linux). Toutes les 60 secondes, il valide le jeton GitHub volé auprès de l'API. Tant que le jeton fonctionne, rien ne se passe. Lorsque la réponse passe en 4xx — c'est-à-dire au moment où vous révoquez le jeton — il exécute, via eval, le contenu de ~/.config/gh-token-monitor/handler : une commande arbitraire définie à distance par l'attaquant. Les analyses publiques ne savent pas ce qu'elle contient — cela pourrait être une destruction de données, une ré-implantation, un rançongiciel, ou rien. Le risque n'est pas évaluable ; c'est pourquoi l'ordre de réponse est absolu.

    Trois propriétés qui changent la réponse :

    • Isoler le réseau est sûr : sans connectivité, il n'y a pas de réponse HTTP, donc pas de 4xx — le piège ne se déclenche pas et l'exfiltration s'arrête. Isolez d'abord, ne coupez pas l'alimentation (la mémoire volatile est une preuve).
    • Il est à usage unique et s'efface de lui-même après déclenchement — le comportement devient inexpliqué, sans artefact laissé pour enquêter.
    • TTL d'environ 24 h : le watcher s'autodétruit après une journée. L'absence d'artefacts ne prouve pas que la machine était saine — le scanner en avertit en mode host.

    Pourquoi les défenses habituelles le manquent généralement

    • « La signature était valide » — [email protected] a été publié avec une attestation SLSA valide. La provenance atteste l'intégrité du build, pas celle de la source : le workflow légitime a compilé un code déjà trojanisé.
    • « Le diff de code n'a pas changé » — exact : la bibliothèque elle-même n'a pas été modifiée. La malveillance se trouve dans package.json (le hook preinstall) et dans deux nouveaux fichiers ajoutés au paquet (setup.mjs, Math_Symbol.js).
    • « Nous n'utilisons pas keyv » — si, indirectement : la chaîne la plus courante est eslint → file-entry-cache → flat-cache → keyv. C'est pourquoi le scanner affiche la chaîne dans chaque résultat.
    • « Personne n'a exécuté npm install » — insuffisant : voir le vecteur B.

    Ce qu'est le script de ce dépôt

    scan.mjs possède les propriétés suivantes — importantes pour quiconque répond à un incident de chaîne d'approvisionnement :

    • Un fichier unique, ~880 lignes lisibles, zéro dépendance. Pas de npm install. Auditez l'intégralité de scan.mjs en 15 minutes avant de l'exécuter.
    • Zéro trafic sortant. Aucune donnée ne quitte votre machine. Pas de télémétrie, pas d'« envoi du résultat pour analyse ». La seule opération réseau est --update (téléchargement d'un nouveau manifeste d'IOC), explicite et facultative.
    • Lecture seule. Le scanner ne modifie, ne supprime ni n'exécute rien de ce qu'il trouve.
    • Fonctionne hors ligne. docker run --network=none ou une machine isolée : il suffit de copier scan.mjs + iocs.json.

    Comment l'utiliser dans votre entreprise

    Prérequis : Node.js ≥ 18 (toute machine avec npm l'a déjà). Téléchargez les deux fichiers — scan.mjs + iocs.json — et c'est tout : aucune installation.

    Attention : si vous avez cloné ce dépôt complet, le dossier fixtures/ contient des IOC inertes utilisés dans les tests (vrais noms et versions, contenu factice — aucun malware). Le scanner l'ignore automatiquement et vous en avertit dans la sortie ; ses résultats n'apparaissent que si vous le scannez exprès.

    Il existe deux modes d'exécution qui répondent à des questions différentes, et c'est ce qui détermine où l'exécuter :

    • Le mode repo lit les lockfiles et node_modules — et les lockfiles vivent dans git, il peut donc être centralisé : une seule personne scanne tous les dépôts de l'entreprise.
    • Le mode host recherche l'implant (watcher, LaunchAgent/systemd, hooks IDE), qui vit sur la machine où le code s'est exécuté — cela ne se trouve pas dans git et ne peut pas être centralisé.

    Étape 1 — L'AppSec scanne tous les dépôts (une personne, une machine)

    root@kitploit:~
    node scan.mjs repo /folder/with/all/the/repos --json=result.json --html=report.html
    

    Répond en quelques minutes à la question « quels projets sont exposés », sans impliquer personne. Accepte plusieurs chemins ; parcourt les sous-répertoires (monorepos et workspaces inclus).

    Étape 2 — quiconque a travaillé sur les projets touchés scanne sa propre machine

    Pour chaque projet avec un résultat, identifiez qui l'a touché depuis 2026-08-04 09:35 UTC (git log, journaux CI). Ces personnes exécutent, sur leur machine :

    root@kitploit:~
    node scan.mjs        # current directory + host, in ~30 seconds
    

    Dans le périmètre : toute personne qui (a) a exécuté npm install/npm ci dans la fenêtre ; ou (b) a simplement cloné et ouvert le dossier dans VS Code ou un agent IA — le vecteur B ne nécessite aucune installation.

    Comme le coût est d'environ 30 secondes et que l'entonnoir peut fuir (un clone égaré, un projet personnel), le message interne le plus sûr est : chaque développeur exécute node scan.mjs une fois et envoie le --json/--html à l'AppSec. L'envoi est manuel par conception — le scanner n'a pas de télémétrie (zéro trafic sortant).

    Étape 3 — Runners CI et serveurs de build

    Priorité absolue : c'est là que vivent les identifiants les plus précieux. Ici, le scanner a deux rôles différents — un pour le passé, un pour l'avenir :

    Triage du passé — ne scannez PAS le runner pour décider. La question « ce runner a-t-il été touché ? » n'est pas résolue par un scan : si un job a installé une version affectée sans --ignore-scripts depuis le 08-04, les identifiants étaient déjà volés à ce moment-là, et l'hôte du runner conserve rarement des preuves (les runners éphémères détruisent le conteneur à la fin du job ; le watcher s'efface de lui-même en ~24 h). Ce qui y répond, ce sont les lockfiles de l'étape 1 et les journaux CI. Si la réponse est « oui, il l'a installé » : reconstruisez le runner et faites pivoter ses secrets — les runners sont éphémères, il n'y a aucune raison de les nettoyer.

    Prévention pour la suite — OUI, exécutez-le dans le pipeline. Ajoutez le scanner comme étape de build, en mode repo, après le checkout et avant npm install. Il n'examine pas l'hôte du runner — il examine le code qui va être installé, et le code de sortie fait échouer le build avant que le preinstall malveillant n'ait une chance de s'exécuter :

    root@kitploit:~
    # example (GitHub Actions / GitLab CI — adapt):
    - run: node scan.mjs repo . --json    # exit 0 clean · 1 findings · 2 COMPROMISED
    - run: npm ci --ignore-scripts         # only runs if the previous step passed
    

    Référence rapide

    root@kitploit:~
    node scan.mjs                     # scan the current directory + the host
    node scan.mjs repo /path/a /path/b
    node scan.mjs host                # persistence/implants on the machine only
    node scan.mjs repo . --json=result.json --html=report.html
    node scan.mjs --update            # update iocs.json (the only network operation)
    

    Triage

    NiveauSignificationAction
    COMPROMISEDVersion malveillante installée dans node_modules, charge utile confirmée par empreinte, ou implant de persistance trouvéTraiter l'hôte comme compromis ; suivre l'ordre de réponse — nettoyer l'implant avant de faire pivoter les identifiants
    EXPOSEDVersion malveillante épinglée dans un lockfile, aucune preuve d'exécutionÉpingler une version sûre, supprimer node_modules, réinstaller avec --ignore-scripts
    AT_RISKPlage (^/~) dans package.json qui admet une version malveillanteÉpingler une version exacte ou la bloquer au proxy de registre
    SUSPECTHeuristique (nom de fichier du ver avec une empreinte non concordante, script de cycle de vie suspect)Inspecter manuellement — peut être une nouvelle variante ou un faux positif
    INFOVecteur présent mais aucun IOC (p. ex. une tâche folderOpen générique)Examiner

    Le rapport comme preuve

    --html produit un rapport autonome avec un horodatage, le nom d'hôte, la version du manifeste d'IOC et le SHA-256 du scanner lui-même — utilisable comme pièce jointe à une notification d'incident et comme piste d'audit.

    Si le scanner a signalé COMPROMISED : l'ordre de réponse

    Ne révoquez et ne faites pivoter aucun identifiant pour l'instant — c'est le déclencheur du piège. La séquence :

    1. ISOLEZ — coupez la machine du réseau. C'est sûr : sans réponse HTTP, il n'y a pas de 4xx, le piège ne se déclenche pas et l'exfiltration s'arrête. Ne coupez pas l'alimentation (la mémoire volatile est une preuve).

    2. PRÉSERVEZ — avant de supprimer quoi que ce soit (le watcher s'autodétruit en ~24 h) :

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

    Le fichier handler est la commande de l'attaquant qui serait exécutée — ne l'exécutez pas, ne la collez pas dans un shell ; traitez-le comme un texte inerte. Le fichier started_at délimite la fenêtre d'exposition (l'auditeur et le régulateur vous le demanderont).

    3. ÉRADIQUEZ — tuez d'abord le processus du watcher, puis :

    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
    
    # both
    rm -rf ~/.config/gh-token-monitor ~/.local/bin/gh-token-monitor.sh /tmp/bun-dl-*
    

    Supprimez également les hooks malveillants de .claude/settings.json et .vscode/tasks.json, les fichiers setup.mjs/Math_Symbol.js/math_init.js, et videz les caches (~/.npm/_cacache, pnpm, yarn). Réexécutez node scan.mjs host jusqu'à ce qu'il revienne propre.

    4. FAITES PIVOTER — seulement une fois chaque hôte affecté nettoyé et vérifié (un seul watcher vivant suffit à déclencher le piège). Révoquez d'abord le jeton npm (cela empêche le ver de se propager) ; puis GitHub (PAT, clés de déploiement), AWS/GCP/Azure, Vault, Kubernetes, les secrets CI — et tout secret présent sur le disque, car il y a eu un balayage regex.

    5. AUDITEZ — le ver agit en votre nom : recherchez les dépôts décrits Shai-Hulud: Here We Go Again dans vos organisations, les versions npm publiées de manière inattendue depuis le 08-04 (dépréciez-les et notifiez les consommateurs), et l'utilisation des identifiants dans CloudTrail/Journaux d'audit dans la fenêtre started_at.

    Ensuite : supprimez node_modules, réinstallez à partir d'un lockfile propre avec --ignore-scripts. Runners CI et hôtes avec exécution confirmée : reconstruisez de zéro, toujours — du code arbitraire s'est exécuté, et la liste des artefacts connus ne garantit pas l'exhaustivité.

    Institutions réglementées (BR) : une compromission confirmée avec accès à des identifiants peut déclencher des obligations de signalement (Res. CMN 4.893/2021, Res. BCB 85/2021 ; LGPD art. 48 si des données personnelles sont impliquées). Documentez la chronologie en UTC — started_at, détection, confinement, éradication, rotation — et confirmez les délais avec le service juridique/conformité.

    Mise à jour des IOC (utilisateurs)

    L'incident est actif et la liste s'allonge. Pour récupérer le dernier manifeste :

    root@kitploit:~
    node scan.mjs --update          # the only operation that touches the network
    

    --update récupère iocs.json depuis ce dépôt (securest8/npm-incident-response), jamais depuis un tiers — Securest8 est la passerelle de curation. Vous obtenez ce qui a été publié en dernier ici.

    Maintenance des IOC (mainteneurs)

    La liste des paquets provient du flux public Wiz ; les empreintes, domaines C2, IOC de persistance et versions sûres sont statiques et organisés dans tools/gen-iocs.mjs. Un instantané du CSV Wiz se trouve dans tools/keyv-packages.csv pour la reproductibilité et les exécutions hors ligne.

    root@kitploit:~
    node tools/gen-iocs.mjs               # fetch the latest Wiz CSV, regenerate iocs.json + refresh the snapshot
    node tools/gen-iocs.mjs --offline     # regenerate from the committed snapshot, no network
    node tools/gen-iocs.mjs --allow-shrink # allow a package count lower than the snapshot (guarded by default)
    

    Le générateur est idempotent : il conserve le manifest_version existant et ne réécrit pas le fichier lorsque rien de substantiel n'a changé, et il refuse d'écrire un manifeste vide ou réduit (protection contre un flux amont tronqué ou modifié).

    Automatisation : .github/workflows/update-iocs.yml exécute le générateur quotidiennement (et à la demande) et ne fait de commit vers main que lorsque les IOC changent réellement — ainsi le --update des utilisateurs suit le flux Wiz en environ une journée, avec tout l'historique auditable dans les commits. Basculez-le en étape de pull request (noté dans le workflow) une fois l'incident calmé et si vous voulez une fusion manuelle à la place.

    Tests

    root@kitploit:~
    node test/run-tests.mjs         # 15 assertions against fixtures/demo-repo
    

    fixtures/demo-repo est un dépôt de test avec des IOC inertes (vrais noms et versions, contenu factice — aucun malware). Lors du scan du dépôt du scanner lui-même, le dossier fixtures/ est ignoré automatiquement (avec un avertissement dans la sortie) ; les tests le scannent en passant explicitement le chemin.

    Périmètre et crédits

    Un outil dédié à un incident unique, conçu pour un triage rapide pendant la fenêtre active de l'attaque — pas un remplaçant de Socket, Snyk ou équivalent. Recherche et IOC : Socket.dev, Wiz Research (CSV public), Kodem Security.

    Maintenu par Securest8. Licence MIT.

    Télécharger l’outil