Prise de contrôle du scope npm Mastra : un compte de mainteneur dormant empoisonne un framework d'agents IA
Le 17 juin 2026, un compte de contributeur oublié a republié tout le scope npm @mastra — environ 142 paquets — avec une dépendance malveillante qui installe un voleur de cryptomonnaie et un RAT. Un identifiant périmé, pas un zero-day.
De quoi s’agit-il ?
Le 17 juin 2026, un attaquant a republié l’intégralité du scope npm @mastra — l’espace de noms de Mastra, un framework TypeScript open source populaire pour construire des agents IA — en injectant une unique dépendance malveillante dans chaque paquet. La bibliothèque injectée, easy-day-js, est un clone de dayjs dont le hook d’installation télécharge et exécute un voleur de cryptomonnaie multiplateforme et un cheval de Troie d’accès à distance (RAT). La compromission a été divulguée le jour même par plusieurs éditeurs, dont Snyk, SafeDep, Endor Labs, ainsi que JFrog, Socket et StepSecurity (via The Hacker News).
Aucun CVE n’a été attribué et le code source de Mastra n’a jamais été modifié. Il ne s’agit pas d’un bug de code. Le point d’entrée était un identifiant de mainteneur dormant : le scope @mastra était publié via le compte npm ehindero, celui d’un véritable ancien contributeur de Mastra dont l’accès en publication n’a jamais été révoqué. npm n’expire pas les permissions de scope en cas d’inactivité : un seul identifiant périmé a donc suffi pour pousser sur chaque paquet de l’espace de noms. Comme le résume Snyk, la cause racine relève de l’hygiène projet, pas d’un zero-day.
Comment ça marche
L’attaque se cachait dans l’arbre de dépendances, pas dans le code. L’attaquant a d’abord publié, le 16 juin 2026, une version propre et parfaitement fonctionnelle de easy-day-js@1.11.21 — un imitateur de dayjs au octet près, jusqu’au dayjs.min.js embarqué et à la description du paquet — pour servir de couverture. Le lendemain, vers 01:01 UTC le 17 juin, il a publié easy-day-js@1.11.22 contenant le malware, en la taguant latest. Chaque version @mastra empoisonnée ajoutait exactement une ligne à son package.json publié :
"easy-day-js": "^1.11.21"
La plage avec caret est l’astuce : 1.11.22 satisfait ^1.11.21, donc un npm install ordinaire résout directement vers la version armée. La dépendance n’est jamais importée par le code de Mastra ; elle n’existe que pour tirer le cheval de Troie à l’installation. Entre 01:12 et 02:36 UTC environ — une rafale automatisée d’environ 88 minutes — le reste du scope a été republié. La remédiation de Mastra dénombre précisément le rayon d’impact : 142 paquets publiables sur @mastra/*, plus mastra, create-mastra et mastracode ; les décomptes publics allaient de 80 à 144 selon l’instantané.
Le malware s’exécute depuis un hook postinstall. À l’installation, il désactive la validation des certificats TLS (NODE_TLS_REJECT_UNAUTHORIZED='0'), télécharge une charge de seconde étape depuis une IP brute via un certificat auto-signé (23.254.164[.]92:8000), l’écrit dans un répertoire temporaire, la lance en processus d’arrière-plan détaché et caché, puis s’autodétruit pour réduire les traces. La seconde étape est un voleur d’informations obfusqué qui lit les profils Chrome, Brave et Edge à la recherche d’une liste codée en dur de plus de 160 extensions de portefeuilles de cryptomonnaie (MetaMask, Phantom, Solflare, Coinbase Wallet, OKX, Keplr), collecte des métadonnées de l’hôte et l’historique de navigation, et émet un battement vers un C2 RAT distinct (23.254.164[.]123) environ toutes les 10 minutes. Il installe une persistance déguisée en outillage Node sur les trois plateformes : un LaunchAgent sur macOS, un service utilisateur systemd sur Linux et un chemin de staging C:\ProgramData\NodePackages sur Windows.
Pourquoi c’est important
Parce que la charge s’exécute au moment de l’installation, l’exposition ne se limite pas à la production. Runners CI, agents de build éphémères et postes de développeurs entrent tous dans le périmètre dès qu’ils résolvent une version empoisonnée. @mastra/core totalise environ 4 millions de téléchargements par mois et compte des centaines de projets dépendants : la portée agrégée se chiffre en dizaines de millions d’installations.
Mastra se situe exactement là où les attaquants de chaîne d’approvisionnement veulent être : à l’intersection du développement IA et de l’infrastructure cloud. Comme le note StepSecurity, ses paquets sont couramment installés dans des environnements détenant certains des identifiants les plus sensibles du logiciel moderne — et pour un framework d’agents, cela signifie des clés d’API de fournisseurs LLM aux côtés des clés cloud, secrets CI et clés SSH. Un voleur de portefeuilles et d’identifiants atterrissant dans ce contexte constitue une cible quasi idéale. Fait notable : Mastra générait des attestations de provenance SLSA sur ses publications CI mais ne les exigeait pas ; un simple jeton personnel pouvait donc publier sans attestation — et l’a fait.
Défenses
Désactivez les scripts d’installation par défaut. Définir npm config set ignore-scripts true neutralise les droppers postinstall comme celui-ci ; vous ne réactivez les scripts que pour les rares paquets qui en ont réellement besoin.
Versionnez les lockfiles et compilez avec npm ci. Un lockfile épinglé à une version antérieure à l’incident garantit qu’un npm ci n’aurait jamais résolu la version armée easy-day-js@1.11.22. Une plage trop large, un lockfile absent ou toute installation fraîche à partir du 17 juin sont précisément ce qui laisse la plage avec caret se ré-résoudre silencieusement.
Exigez la provenance, ne vous contentez pas de la générer. Une installation qui vérifie les signatures — npm audit signatures, ou une politique rejetant les paquets sans attestation — aurait refusé chaque paquet de cette vague, car l’attaquant a abandonné la provenance que produit normalement le pipeline CI légitime.
Surveillez les dépendances fantômes. Un paquet mûr et largement utilisé qui gagne soudain une unique dépendance non utilisée est exactement le signal ici. Traitez-le comme un drapeau rouge en revue et en politique automatisée.
Révoquez les accès de mainteneurs périmés. Auditez qui peut publier sur vos scopes, retirez les comptes dormants, et imposez la 2FA et les flux de publication de confiance. Tout l’incident a reposé sur un identifiant que personne n’avait retiré.
Si vous avez résolu une version empoisonnée, considérez l’hôte comme compromis : passez à une version saine connue (par exemple @mastra/core@1.42.0 ou supérieure — n’épinglez pas simplement vers le bas, car l’attaquant a publié certaines versions au-dessus du latest légitime), faites tourner tous les identifiants que la machine pouvait atteindre (cloud, CI, npm, SSH, et surtout clés d’API LLM), déplacez les portefeuilles crypto vers un appareil propre, supprimez les artefacts de persistance, et réinstallez le système quand c’est possible.
Statut
| Élément | Détail |
|---|---|
| Incident | Prise de contrôle du scope npm @mastra, republication massive avec dépendance injectée |
| Date | 17 juin 2026 (leurre easy-day-js@1.11.21 publié le 16 juin) |
| Paquet malveillant | easy-day-js@1.11.22 (dropper) ; marqueur easy-day-js@1.11.21 (leurre propre) |
| Cause racine | Compte npm d’ancien contributeur dormant (ehindero), accès en publication jamais révoqué |
| Rayon d’impact | ~142 paquets publiables @mastra/* ; décomptes publics 80–144 |
| Charge utile | Voleur de portefeuilles crypto + RAT avec persistance, multiplateforme |
| CVE / CVSS | Aucun attribué ; code source non modifié, malveillance introduite à la publication |
| Statut | Versions malveillantes retirées ; versions propres publiées en avance le jour même (ex. @mastra/core@1.42.0) |
Sources
- → https://snyk.io/blog/a-forgotten-contributor-account-compromised-the-entire-mastra-npm-package-scope/
- → https://thehackernews.com/2026/06/144-mastra-npm-packages-compromised-via.html
- → https://safedep.io/mastra-npm-scope-takeover-supply-chain-attack/
- → https://www.endorlabs.com/learn/mastra-npm-org-compromised-multiple-packages-trojanized-to-drop-a-remote-payload-via-easy-day-js