En juillet 2025, je prototypais un nouveau projet et j'ai décidé d'essayer MikroORM. La documentation indiquait d'exécuter npx mikro-orm-esm pour les migrations. Ce que j'ai fait.
npm ERR! code E404
npm ERR! 404 Non trouvé - GET https://registry.npmjs.org/mikro-orm-esmLe paquet n'existe pas, c'est étrange ! Puis j'ai réalisé : et si quelqu'un l'avait enregistré ? J'aurais vu :
Les paquets suivants doivent être installés :
mikro-orm-esm@1.0.0
Continuer ? (o)J'aurais simplement tapé o. Tout le monde le fait. Et rien dans cette invite ne vous indique si vous êtes sur le point d'installer un logiciel malveillant ou un outil légitime.
La documentation faisait référence à un paquet inexistant. Combien d'autres références à des paquets Phantom circulent ? Combien ont déjà été revendiquées par des attaquants ? Je devais le savoir.
J'ai donc commencé à creuser. J'ai écrit des scripts pour scanner npm à la recherche de paquets référencés dans READMEs et scripts mais jamais réellement publiés. J'ai recoupé des milliers d' npx invocations. J'en ai trouvé des dizaines. J'en ai revendiqué 14 avant que quiconque ne puisse le faire. Puis S1ngularity est arrivé, et la recherche a été mise de côté.
Six mois plus tard, ma recherche m'a été rappelée grâce à la communauté qui faisait des recherches similaires. J'ai finalement vérifié le nombre de téléchargements : 121 539 téléchargements !
Les gens avaient exécuté ces commandes inexistantes des milliers de fois par semaine. Pendant des mois. Pendant que les paquets restaient là à collecter des données.
Six mois de données
Les téléchargements ne sont pas restés stables. Ils ont augmenté. Le démarrage a été lent fin juillet. Le pic récent a atteint 4 236 téléchargements en une seule journée (16 janvier 2026).
- Total : 121 539 téléchargements pour 128 packages
- Moyenne hebdomadaire : 3 903
- Jour de pointe : 4 236 téléchargements (16 janv. 2026)
Petite remarque sur le bruit : chaque fois que vous publiez une nouvelle version d'un package, elle génère automatiquement 60 à 100 téléchargements provenant de scanners de sécurité et de miroirs. C'est le bruit de base par version. Les packages avec plusieurs versions accumulent rapidement ce bruit. Tout ce qui dépasse constamment ce seuil correspond à une utilisation réelle.
Remarquez la baisse fin décembre ? Ce sont les vacances. Même les téléchargements de packages Phantom prennent des congés à Noël.
Les Trois Grands
Trois packages représentent 79 % de tous les téléchargements :
openapi-generator-cli: 48 356 téléchargements (package réel : @openapitools/openapi-generator-cli)cucumber-js: 32 110 téléchargements (package réel :@cucumber/cucumber)depcruise: 15 637 téléchargements (package réel :dependency-cruiser)
openapi-generator-cli a enregistré 3 994 téléchargements au cours des 7 derniers jours seulement. C'est près de 4 000 fois que quelqu'un a tenté d'exécuter une commande inexistante. En une semaine.
La longue traîne
Les packages restants avec un nombre significatif de téléchargements :
jsdoc2md: 4 641 téléchargementsgrpc_tools_node_protoc: 4 518 téléchargementsvue-demi-switch: 1 166 téléchargementsstyleguidist: 805 téléchargementsmikro-orm-esm: 314 téléchargementspvbase64: 142 téléchargementscromwell: 106 téléchargements
Vous vous souvenez de cette base de 60 à 100 téléchargements par version ? Un package avec 3 versions pourrait générer 180 à 300 téléchargements de pur bruit. fathym avec 83 téléchargements au total est probablement du pur bruit. Mais mikro-orm-esm avec 314 ? Même en tenant compte de plusieurs versions, ce sont de véritables tentatives.
styleguidist avec 805 téléchargements signifie des centaines d'exécutions réelles. Il pourrait s'agir de CI/CD qui le sollicite à plusieurs reprises. Il pourrait s'agir de dizaines de développeurs différents. Dans tous les cas, c'est une utilisation réelle d'un package qui ne devrait pas exister.
Comment nous les avons trouvés
Nous gérons un miroir complet du registre npm chez Aikido. Nous avons analysé chaque package.json et README sur l'ensemble du registre. Nous avons extrait npx commandes. Nous avons recoupé ces informations avec ce qui est réellement enregistré. Nous avons également effectué des recherches dans le code de GitHub pour voir à quel point ces commandes Phantom apparaissent dans la nature, dans la documentation, les configurations CI, les scripts, partout où les développeurs pourraient y faire référence.
Trois points de données pour chaque package :
- Références du registre : Combien de packages npm mentionnent cette commande dans leur package.json ou README
- Résultats GitHub : Combien de fichiers de code ou de dépôts référencent cette commande sur GitHub
- Téléchargements : Combien de fois des personnes ont réellement tenté de l'exécuter
Nous en avons revendiqué 14 en juillet 2025. Lorsque j'ai repris la recherche en janvier, nous avons étendu notre analyse et en avons trouvé beaucoup plus. À ce jour, nous avons revendiqué 128 packages au total.
Quelques schémas à noter :
Vecteurs d'attaque majeurs (plus de 10 000 téléchargements) : openapi-generator-cli, cucumber-js, et depcruise tous montrent une forte corrélation entre les références npm, les mentions GitHub et les téléchargements réels. Ceux-ci seraient dévastateurs entre les mains d'un attaquant.
Forte exposition, faible conversion : styleguidist compte 246 références npm et 286 résultats GitHub, mais seulement 805 téléchargements. git-scripts-pre-push compte 126 références mais seulement 93 téléchargements. La visibilité n'équivaut pas toujours à l'exécution.
Vecteurs basés uniquement sur la documentation : mikro-orm-esm n'a aucune référence de package npm mais 80 résultats GitHub et 314 téléchargements. Preuve que la documentation seule peut générer des centaines d'installations, même sans aucune référence dans l'écosystème npm.
Pourquoi c'est dangereux
L'attaque est simple.
Un attaquant enregistre le package. Ajoute un post-installation script qui exfiltre les variables d'environnement : jetons npm, identifiants cloud, clés API, tout ce qui traîne. Puis attend.
Au plus fort, cela représente potentiellement environ 4 000 machines compromises par semaine. Postes de travail de développeurs. Serveurs CI. Environnements de build. Beaucoup fonctionnent probablement avec des identifiants dans des variables d'environnement. Aucun phishing n'est nécessaire. Aucun compromis de la chaîne d'approvisionnement des packages existants. Il suffit de revendiquer le nom et d'attendre que npx vous amène les victimes.
Quand quelqu'un exécute la commande, il voit :
Besoin d'installer les packages suivants :
openapi-generator-cli@1.0.0
Continuer ? (o)L'invite ne montre pas qui l'a publié. Ne montre pas quand. Ne montre pas si c'est ce que vous cherchez. Vous pourriez voir cette invite régulièrement pour des outils légitimes. La mémoire musculaire prend le dessus, car nous sommes humains. Vous tapez o, comme tout le monde le fait. C'est tout. C'est toute l'attaque.
Nous avons comblé 128 lacunes sur plusieurs cycles. Nous avons identifié les pires cas. Mais il y a une longue traîne de milliers.
Une note sur les protections de npm
npm dispose d'une protection contre le typosquatting. Lorsque nous avons tenté de revendiquer certains noms, npm les a rejetés en raison d'erreurs de similarité. Des noms comme rsbuild, vuedoc, napi, t-ci étaient tous trop proches de paquets existants. C'est une bonne chose. Cela signifie que npm bloque activement les tentatives de squatting évidentes.
Mais ces commandes Phantom ne sont pas des fautes de frappe. Ce sont des noms qui n'ont jamais été enregistrés à l'origine. La vérification de similarité de npm ne les détecte pas car il n'y a rien à quoi être « similaire ».
Ce qu'il faut faire
Utilisez npx --no-install
npx --no-install votre-commandeCela force npx à n'utiliser que les binaires locaux. Pas de repli sur le registre. S'il n'est pas installé, il échoue. C'est ce que vous voulez.
Installez les outils CLI explicitement. Ne vous fiez pas à npx pour les récupérer :
{
"devDependencies": {
"@openapitools/openapi-generator-cli": "^2.7.0"
}
}
Vérifiez avant d'exécuter. La documentation indique d'exécuter npx quelque chose ? Vérifiez d'abord que le paquet existe réellement. Vérifiez que c'est le bon. Surtout en CI/CD.
Revendiquez votre espace de noms. Si vous maintenez un outil CLI, enregistrez les alias et les fautes d'orthographe évidentes. Une assurance bon marché contre toute action malveillante d'autrui.
Comment savoir si vous êtes concerné
Si vous êtes un utilisateur Aikido, vérifiez votre flux central et filtrez les problèmes de logiciels malveillants. Toute vulnérabilité de paquet Phantom apparaîtra comme un problème critique 100/100 dans le flux. Aikido rescane vos dépôts chaque nuit, bien que nous recommandions de déclencher également un rescan complet.
Si vous n'êtes pas encore un utilisateur Aikido, créez un compte gratuit et connectez vos dépôts. Notre couverture propriétaire des logiciels malveillants est incluse dans le plan gratuit (aucune carte de crédit requise).
Pour une protection future, envisagez d'utiliser Aikido SafeChain (open source), un wrapper sécurisé pour npm, npx, yarn et pnpm. SafeChain s'intègre à vos workflows actuels, interceptant les commandes d'installation de paquets et vérifiant les paquets par rapport à Aikido Intel (notre renseignement sur les menaces open source) avant qu'ils n'atteignent votre machine. Arrêtez les menaces à la porte.
Les chiffres
121 539 téléchargements en sept mois. 3 903 par semaine en moyenne. Pic de 4 236 en une seule journée. 128 paquets revendiqués au total (14 en juillet, le reste en janvier).
L'écosystème npm compte des millions de paquets. Les développeurs exécutent des commandes npx des milliers de fois par jour. L'écart entre le « défaut pratique » et l'« exécution de code arbitraire » est un nom de paquet non revendiqué.


