CanisterWorm : TeamPCP compromet des packages NPM via un ver auto-propageable avec C2 ICP

🎯 Contexte Publié le 20 mars 2026 par Aikido Security (Charlie Eriksen), cet article documente la détection le 20 mars 2026 à 20h45 UTC d’une campagne de compromission massive de packages NPM, baptisée CanisterWorm, attribuée au groupe TeamPCP. Cette attaque fait suite à une compromission de l’outil Trivy moins de 24 heures auparavant, documentée par Wiz. 📦 Packages compromis 28 packages dans le scope @EmilGroup 16 packages dans le scope @opengov @teale.io/eslint-config @airtm/uuid-base32 @pypestream/floating-ui-dom 🏗️ Architecture en trois étapes Stage 1 – Loader Node.js (postinstall) : Un hook postinstall dans index.js décode un payload base64 (script Python), crée un service systemd utilisateur pgmon.service avec Restart=always, et le démarre immédiatement. Aucun accès root requis. Stage 2 – Backdoor Python persistante : Le script service.py attend 5 minutes (évasion sandbox), puis interroge toutes les ~50 minutes un canister ICP (tdtqy-oyaaa-aaaae-af2dq-cai.raw.icp0.io) pour obtenir une URL de payload. Il télécharge le binaire vers /tmp/pglog, l’exécute en processus détaché, et sauvegarde l’URL dans /tmp/.pg_state. Un kill switch est intégré : si l’URL contient youtube.com, le payload est ignoré. Stage 3 – Ver de propagation (deploy.js) : Outil initialement manuel utilisant des tokens NPM volés pour énumérer tous les packages publiables d’un compte, incrémenter la version patch, préserver le README original, et republier avec --tag latest. 🐛 Évolution vers l’auto-propagation Environ une heure après la vague initiale, une mise à jour de @teale.io/eslint-config (versions 1.8.11 et 1.8.12) a introduit la fonction findNpmTokens() qui : ...

25 mars 2026 · 3 min
Dernière mise à jour le: 26 Mar 2026 📝