Guide de détection et remédiation : compromission npm jscrambler (IronWorm)

Ce guide s'adresse à quelqu'un qui doit vérifier/nettoyer une machine, pas à des analystes. Il s'appuie sur jscrambler-npm-supplychain.md ; ce que je n'ai pas vérifié moi-même (et qui vient seulement de sources tierces) est signalé comme tel.

1. Suis-je concerné ?#

Vous êtes concerné si un projet Node.js sur cette machine a installé une des versions suivantes du package jscrambler entre le 11/07/2026 15:12 UTC et 18:12 UTC :

8.14.0, 8.16.0, 8.17.0, 8.18.0, 8.20.0

(8.15.0 et les versions ≤8.13.0/≥8.22.0 sont saines.)

Vérification rapide#

# Cherche toutes les installations de jscrambler sur le système, versions incluses
find / -path "*/node_modules/jscrambler/package.json" -exec grep -H '"version"' {} \; 2>/dev/null

# Si un gestionnaire de version Node est utilisé, répéter dans chaque environnement
# (nvm, volta, asdf, etc. isolent souvent des node_modules différents)

Ou, avec les règles YARA fournies dans ce dossier (tools/ironworm.yar) :

yara -r tools/ironworm.yar /chemin/vers/node_modules/

Un match sur NPM_jscrambler_IronWorm_container ou NPM_jscrambler_IronWorm_js_loader confirme la présence du code malveillant, indépendamment du numéro de version exact installé.

2. Signes d'infection active#

Persistance Windows (que j'ai confirmée dans le binaire, template XML complet trouvé en clair dans .rdata, voir jscrambler-npm-supplychain.md §7.1) : tâche planifiée cachée (<Hidden>true</Hidden>), relance toutes les minutes (PT1M) jusqu'à 999 tentatives (<RestartOnFailure>).

Get-ScheduledTask | Where-Object { $_.Settings.Hidden -eq $true } | Format-List TaskName, Actions

Persistance macOS (idem, non revérifiée directement) : LaunchAgent avec RunAtLoad/KeepAlive, intervalle ~30s.

ls -la ~/Library/LaunchAgents/ /Library/LaunchAgents/
# inspecter tout .plist non reconnu, chercher RunAtLoad + KeepAlive + StartInterval~30

Linux : aucun mécanisme de persistance identifié dans cette investigation à ce stade (ni par moi, ni par les sources tierces consultées), n'en déduisez pas qu'il n'y en a pas, juste que ça reste une inconnue ouverte (voir jscrambler-npm-supplychain.md §9).

Toutes plateformes : le binaire natif dropped est écrit dans le répertoire temporaire système (os.tmpdir()) sous un nom aléatoire commençant par un point (.xxxxxxxx, ou .xxxxxxxx.exe sur Windows). Cherchez des exécutables récents et non reconnus dans :

Linux/macOS : /tmp/.* 
Windows     : %TEMP%\.* 

3. Nettoyage#

  1. Coupez l'accès réseau de la machine avant toute autre action si une exécution du payload est suspectée (processus persistant actif), le protocole C2 confirmé ({"t":"out"/"done",...}, voir jscrambler-npm-supplychain.md §6) suggère une exfiltration active tant que le process tourne.
  2. Tuez tout processus correspondant à un binaire suspect trouvé en §2 (nom aléatoire dans le répertoire temp).
  3. Supprimez la tâche planifiée Windows / le LaunchAgent macOS identifiés en §2.
  4. Supprimez node_modules/jscrambler (et tout package-lock.json/yarn.lock/pnpm-lock.yaml qui référence encore une version malveillante) dans tous les projets de la machine, pas seulement celui repéré en premier.
  5. Réinstallez jscrambler@8.22.0 ou plus récent uniquement après l'étape 4.
  6. Ne faites pas confiance à la machine elle-même pour la suite. Le GHSA officiel est explicite : une machine ayant exécuté ce code doit être considérée comme totalement compromise, un simple retrait du package ne garantit pas l'absence d'autres implants posés par le payload une fois exécuté.

4. Rotation des secrets : depuis une AUTRE machine#

À faire uniquement depuis un poste non compromis, jamais depuis la machine infectée elle-même :

Catégorie Action
Mots de passe/cookies navigateur (Chrome/Chromium/Brave/Edge) Changer tous les mots de passe enregistrés, déconnecter toutes les sessions actives des comptes concernés
Bitwarden (et autres gestionnaires de mots de passe utilisant LevelDB accessible) Changer le mot de passe maître, vérifier l'historique de connexion du compte
Steam Déconnecter toutes les sessions actives, changer le mot de passe, vérifier l'historique de connexion
AWS (Secrets Manager, SSM Parameter Store, credentials de rôle EC2/IMDS) Faire tourner (rotate) toutes les clés IAM et secrets accessibles depuis la machine, réviser les rôles IAM attachés à toute instance EC2 concernée
HashiCorp Vault Révoquer les tokens/leases émis à la machine concernée, faire tourner les secrets lus
Discord, Slack, VS Code (via extraction ASAR Electron) Déconnecter les sessions, changer les mots de passe, régénérer les tokens d'application si applicable
Wallets crypto (seed phrases BIP-39) Si une seed phrase a pu être stockée en clair ou copiée/collée sur la machine infectée, considérer les fonds comme compromis et transférer vers un nouveau wallet créé sur une machine saine
Token de publication npm (si la machine publie des packages) Révoquer et régénérer immédiatement, c'est exactement le vecteur d'entrée initial de cette compromission

5. Signal réseau : trafic Tor sortant#

Le C2 réel (confirmé par une source tierce, JFrog, voir jscrambler-npm-supplychain.md §7.4, que je n'ai pas vérifié moi-même) passe par un service caché Tor : le malware télécharge et lance son propre démon Tor local, puis fait du beaconing HTTP à l'intérieur du tunnel chiffré. Ça veut dire :

  • Il n'y a pas de domaine ou IP C2 fixe à bloquer, bloquer une IP ne sert à rien contre un C2 Tor
  • Le signal de détection réseau le plus fiable est la présence de trafic Tor sortant (port 9001/9050 typiques, ou trafic vers des relais Tor connus) depuis une machine qui ne devrait normalement pas en faire
  • Si votre organisation bloque déjà Tor par politique, une alerte sur ce blocage précis, sur une machine de développement, est un signal fort

6. Ce qui n'est pas couvert par ce guide#

  • Persistance Linux (non confirmée, §2)
  • Le mécanisme d'auto-propagation éventuel vers d'autres packages (non tracé, jscrambler-npm-supplychain.md §8)
  • L'adresse .onion réelle du C2 (jamais obtenue, ni par moi ni par les sources consultées, la config qui la contiendrait reste chiffrée)

Ce document sera mis à jour si ces inconnues sont levées.