Attaque de typosquatting DevTap npm

Attaque de typosquatting DevTap npm : six packages malveillants ciblent les postes de travail des développeurs

TL; DR

Entre le 1er avril et le 3 mai 2026, un seul éditeur npm, user0001, enregistré avec l'adresse Gmail non vérifiée tanvisoul9@gmail.com, ont discrètement fait passer six paquets aux noms délibérément fades, évoquant l'infrastructure : centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime et node-env-resolve.

Les deux dernières versions de node-env-resolve, 1.0.7 et 1.0.8, ont été signalés par le système d'alerte précoce aux logiciels malveillants (MEW) de Xygeni le 2 mai et confirmés comme malveillants le 3 mai.

L'implant est inhabituel par ce qu'il n'est pas : il n'y a pas de bots Telegram, pas de rappels OAST, pas de obfuscationet aucune tentative de récupération des identifiants AWS lors de l'installation. Au lieu de cela, postinstall.js installe une entrée de persistance de démarrage Windows, en utilisant une clé d'exécution HKCU qui lance wscript.exe contre un stub VBS. Ensuite, il lance un agent Node.js détaché qui regroupe des modules pour la capture du microphone, le vol de l'historique du navigateur, la capture d'écran et la simulation de la souris/du clavier.

Nous appelons ce cluster DevTap, après que le kit soit installé et fonctionne sur la machine du développeur.

Les six paquets étaient disponibles sur npm au moment de la rédaction. Nous les avons signalés au registre des abus. Les équipes de sécurité doivent retirer toutes les installations en attente de suppression auprès de l'éditeur.

Le Cluster : Six paquets, un éditeur

Le compte de l'éditeur user0001 n'est pas vérifié. Il n'a pas SCM vérification, pas d'adresse e-mail liée à un domaine et aucun historique antérieur. L'identifiant Gmail tanvisoul9 n'apparaît dans aucun autre enregistrement d'éditeur npm que nous ayons pu trouver.

Les six paquets indiquent le même responsable, ont été publiés depuis le même compte et partagent le même package.json texte standard. Il n'y a pas de texte standard. repository, non homepage, et non description plus long qu'une seule ligne.

La stratégie de nommage est l'aspect le plus intéressant. Contrairement aux campagnes classiques de confusion de dépendances ou de typosquatting, aucun de ces noms ne cible une bibliothèque amont spécifique. Au contraire, ils sont conçus pour se fondre dans un véritable package.json or npm ls sortie.

Forfait Première publication Dernière version versions Rôle au sein du groupe
centralogue 2026-04-01 12:46 UTC 1.0.9 5, de 1.0.5 à 1.0.9 Couverture de l'utilitaire de journalisation de Cluster ; première publication
dom-utils-lite 2026-04-14 07:36 UTC 1.0.3 3 Couverture générique d'assistant DOM
node-fetch-lite 2026-04-19 10:22 UTC 1.0.2 3 Imite la famille node-fetch
agent de connecteur 2026-04-25 05:12 UTC 1.0.0 1 Nom générique « agent »
node-gyp-runtime 2026-04-25 05:17 UTC 1.0.0 1 Imite les outils de construction de modules natifs
node-env-resolve 2026-04-25 05:21 UTC 1.0.9 10, de 1.0.0 à 1.0.9 compte-gouttes actif; implant complet

Des noms comme centralogger, node-fetch-lite et node-gyp-runtime Elles sont conçues pour ne pas susciter de controverse lors des revues de code. Elles donnent l'impression d'être des éléments déjà présents dans l'arbre de dépendances d'un projet.

Associés à un éditeur récent et non vérifié et à des liens de dépôt manquants, ces éléments forment un schéma reconnaissable : un acteur insère des noms peu concurrentiels dans le registre, puis itère rapidement sur celui qui compte. Dans ce cas, node-env-resolve J'ai reçu dix versions en huit jours.

Qu'est-ce qui se retrouve sur une boîte de développement Windows ?

La chaîne malveillante sur node-env-resolve:1.0.8 Il est court, direct et exceptionnellement riche en fonctionnalités pour un RAT npm.

Post-installation : persistance et agent détaché

package.json déclare un seul hook d'installation :

{ "scripts": { "postinstall": "node postinstall.js" } }

postinstall.js fait trois choses dans l'ordre.

Tout d'abord, il crée un répertoire d'installation en dehors de l'arborescence npm. Le chemin est calculé à l'exécution dans le script comme suit : INSTALL_DIREnsuite, il exécute un processus interne. execSync('npm install --production --silent ...') Il faut l'intégrer pour récupérer les dépendances d'exécution de l'implant. Cela place l'agent sur le disque à un emplacement manuel. node_modules L'audit ne révélera rien.

Deuxièmement, il écrit un lanceur VBS et l'enregistre pour la persistance au démarrage :

reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run \
    /v ${AGENT_NAME} \
    /t REG_SZ \
    /d "wscript.exe \"${vbsPath}\"" /f

wscript.exe est l'hôte de script Windows, un binaire Microsoft signé qui exécute .vbs fichiers sans fenêtre de console. C'est précisC'est pourquoi il est privilégié pour les stubs à exécution automatique.

Il existe également un assortiment reg delete chemin à l'intérieur src/index.js, ce qui laisse supposer que l'implant est conçu pour être retiré facilement sur commande de l'opérateur.

Troisièmement, il engendre un processus enfant détaché :

spawn(node, [path.join(INSTALL_DIR, 'src/index.js')], {
  detached: true,
  env: { ...process.env, SERVER_URL }
})

Deux détails sont importants ici.

SERVER_URL Les informations sont lues à partir de l'environnement. Par conséquent, le point de terminaison C2 est configurable pour chaque déploiement et n'est pas intégré au package. Ce choix, bien que mineur, est délibéré et permet de contrer la plupart des analyses statiques d'IOC.

De plus, l'enfant engendré hérite de l'environnement complet du parent. Par conséquent, tout NPM_TOKEN, AWS_*, GITHUB_TOKEN, ou le socket de l'agent SSH présent dans le shell du développeur au moment de l'installation voyage dans la mémoire de l'agent à longue durée de vie.

Ce que l'agent expédie avec

Le groupé src/ L'arbre comprend trois modules dont les noms à eux seuls sont révélateurs : audioCapture.js, browserHistory.js et systemInfo.js.

La liste des dépendances d'exécution, résolue lors de la phase d'étape npm install, les corrobore.

Cette approche transforme un incident chaotique en une réponse contrôlée.

Au lieu de réagir à l'aveuglette, les équipes fonctionnent avec Priorisation claire et correction rapide.

Dépendance À quoi cela sert-il dans ce contexte ?
capture d'écran - bureau Capture d'écran périodique
@nut-tree-fork/nut-js Simulation d'automatisation de la souris et du clavier / simulation d'entrée
mieux-sqlite3 Lecture directe des bases de données SQLite de l'historique de Chrome, Edge et Firefox
adm-zip Regroupement des artefacts collectés avant l'exfiltration
net Redimensionnement/compression des captures d'écran et des artefacts d'image
client socket.io Canal C2 bidirectionnel persistant
identifiant de machine de nœud Empreinte digitale stable par hôte pour le suivi des victimes

systemInfo.js en cours os.networkInterfaces() pour une prise d'empreintes digitales supplémentaire avant la première balise.

Pourquoi la capture audio est le signal le plus remarquable

La plupart des RAT npm que nous analysons dans MEW s'arrêtent au vol d'informations lors de l'installation. Ils lisent ~/.npmrc, Lire ~/.aws/credentials, gratter process.envUne requête POST est envoyée à un webhook, puis l'attaquant quitte le site. Ce procédé correspond à un modèle économique de type « attaque éclair ». Les identifiants ont une durée de vie limitée, et l'attaquant doit monétiser rapidement.

node-env-resolve sa forme est différente.

La persistance est configurée pour survivre au redémarrage. L'agent s'exécute de manière autonome et a une longue durée de vie. wscript.exe. Le kit qu'il embarque est conçu pour être installé sur la machine d'un développeur, et non pour être emporté et utilisé rapidement : un enregistreur de microphone, un pilote clavier/souris, l'ingestion complète de l'historique du navigateur, la capture d'écran et un canal Socket.IO interactif vers un C2 configurable.

La capture du microphone en particulier constitue une limite que cette campagne franchit et que la plupart des logiciels malveillants npm ne franchissent pas.

Le poste de travail d'un développeur est de plus en plus souvent celui où se tiennent les réunions quotidiennes, les appels clients, les discussions de conception et les astreintes. Un dispositif d'enregistrement du microphone ne vise pas réellement le jeton npm du développeur, mais plutôt ce qu'il dit devant son ordinateur portable.

Cet ensemble de capacités, ajouté à l'absence d'obfuscation et à l'absence de toute exfiltration spectaculaire lors de l'installation, donne l'impression d'un prépositionnement pour un accès ciblé plutôt que pour un vol d'identifiants opportuniste.

Nous ne fondons pas notre attribution sur ce seul élément. Nous prenons simplement note du profil opérationnel.

Attaque de typosquatting npm - DevTab

La cadence d'itération de huit jours sur node-env-resolve Il s'agit du détail le plus révélateur sur le plan opérationnel dans cette chronologie.

Il ne s'agit pas d'un déploiement automatique. L'éditeur assure la maintenance du programme d'installation, ce qui signifie généralement deux choses : soit il l'optimise sur des environnements de test avant un déploiement plus large, soit il dispose déjà de données de télémétrie d'installation et y répond.

Les cinq autres paquets n'ont pratiquement pas subi de modifications après leur publication initiale. Cela correspond à une approche de type « mise en place unique, nom laissé en place » pour le cluster de support, tandis que les efforts d'ingénierie se concentrent sur le paquet qui effectue le travail.

Attribution : Petits indices, pas de verdict définitif

Public mode OSINT Les signaux sont ténus, et nous ne les étirerons pas. Ce qui est observable :

Le compte Gmail tanvisoul9 Ressemble partiellement à un prénom sud-asiatique, « Tanvi ». C’est un indice faible. Les identifiants Gmail ne constituent pas une identité, et le reste… soul9 est générique. Il n'est pas sûr de déduire la géographie à partir de la seule partie locale d'un courriel.

Le style de code est banal pour Node.js : standard appels de bibliothèque tels que os, child_process, spawn et reg addIl n'y a ni obfuscation, ni rotation de chaînes de caractères, ni logique anti-débogage. L'auteur maîtrise les primitives du registre Windows et l'orchestration de processus enfants détachés, mais ne semble pas recourir à des techniques plus furtives qu'il pourrait plausiblement utiliser.

Les dépendances sont entièrement standard et bien connues : screenshot-desktop, nut-js, better-sqlite3 et socket.io-clientIl n'existe aucun protocole personnalisé, aucune pile C2 développée de toutes pièces, et aucune astuce de persistance inédite au-delà de ce qui est décrit dans les manuels. Clé d'exécution HKCUIl s'agit d'un intégrateur compétent, et non d'un concepteur d'outils.

Nous n'avons trouvé aucune chaîne de caractères non anglaise, aucun commentaire intégré, aucune donnée de localisation ni aucune empreinte de fuseau horaire de sortie du compilateur dans les artefacts publiés.

Nous avons vérifié s'il y avait un chevauchement de code avec les campagnes précédentes que nous suivons déjà, notamment Shai Hulud, Owlivion, Buildkite, et le récent heibai / claude-code-best Famille de clones d'Anthropic-CLI. Nous n'en avons trouvé aucun : ni modèles C2 partagés, ni structures de fichiers partagées, ni idiomes partagés.

Ce que nous ne dirions pas : qu’il s’agit d’un acteur étatique, d’un groupe connu ou d’une entité géographiquement liée à un pays spécifique.

Le profil opérationnel correspond à celui d'une petite équipe aux compétences moyennes, chargée de la surveillance des postes de travail des développeurs. La motivation financière réside probablement dans l'utilisation ultérieure de l'accès, mais il est possible qu'il s'agisse également d'un service de reconnaissance proposé à un autre client.

Deux arguments indirects appuient cette affirmation : l’évitement de mécanismes d’exfiltration accrocheurs qui pourraient rapidement compromettre le cluster, tels que les bots Telegram, oastify.com, ou jetons canari, et les noms de paquets délibérément neutres, qui privilégient les installations discrètes et à long terme plutôt qu'un pic bref et important.

Indicateurs de compromission et de détection

Packages et éditeur
Champ Valeur
éditeur npm user0001
Courriel de l'éditeur tanvisoul9@gmail.com, non vérifié
Forfaits centralogger, dom-utils-lite, node-fetch-lite, connector-agent, node-gyp-runtime, node-env-resolve
Malveillance confirmée node-env-resolve@1.0.7, node-env-resolve@1.0.8
Artefacts de l'hôte
Type Valeur
Clé de persistance HKCU\Software\Microsoft\Windows\CurrentVersion\Run
Valeur de persistance Nom de la variable ; données de la forme wscript.exe " \\ .vbs"
Installer le crochet postinstall : fichier node postinstall.js dans le manifeste du package
modules implantables src/audioCapture.js, src/browserHistory.js, src/systemInfo.js
Répertoire de préparation Le répertoire INSTALL_DIR est résolu en dehors du répertoire node_modules du projet ; son emplacement est défini par postinstall.js lors de l'installation.
Réseau
Type Valeur
Transport C2 client socket.io, canal bidirectionnel persistant
Point final C2 Fournie à l'agent via la variable d'environnement SERVER_URL ; non codée en dur dans les artefacts publiés

Notes de détection

Deux règles permettent de détecter cette famille sans avoir besoin du point de terminaison C2.

Tout d'abord, signalez les scripts post-installation qui effectuent une opération interne. npm install dans un chemin situé en dehors du répertoire du paquet. Tout programme de téléchargement de précompilations légitime, tel que node-gyp reconstruit ou télécharge des binaires précompilés, écrit à l'intérieur du paquet ou dans la plateforme-standard Les chemins de cache sont associés à des hachages vérifiés. L'écriture n'est pas effectuée dans un fichier nouvellement créé. INSTALL_DIR ailleurs sur le disque.

Deuxièmement, signalez les scripts post-installation qui posent problème. reg add HKCU\…\Run au wscript.exe en tant que lanceur. Cela n'est jamais légitime pour un paquet npm. Signalez-le et mettez-le en quarantaine.

Une troisième heuristique est utile pour repérer le prochain paquet frère avant sa confirmation : un nouvel éditeur npm sans SCM vérification, une adresse e-mail Gmail, non repository Le fait qu'un champ et plusieurs noms de paquets courts, génériques et à consonance infrastructurelle soient publiés à quelques jours d'intervalle suffit à justifier un examen manuel.

Signalé au registre npm. Nous mettrons à jour cet article dès que le compte de l'éditeur sera supprimé.

sca-tools-logiciel-outils-d'analyse-de-composition
Priorisez, corrigez et sécurisez vos risques logiciels
Essai gratuit 7 jours
Aucune carte de crédit requise

Sécurisez le développement et la livraison de vos logiciels

avec la suite de produits Xygeni