
Dossier technique sur l'attaque de la chaîne d'approvisionnement PolinRider liée à la Corée du Nord, documentant l'injection de payload JS obfusqué, la manipulation de l'historique Git, l'infrastructure C2 et des conseils de remédiation pour 1 951 dépôts compromis.

L'équipe OpenSourceMalware a découvert une vaste campagne de menace qui implante des malwares dans les dépôts des utilisateurs et organisations GitHub. L'acteur de menace, PolinRider, a implanté des charges utiles JavaScript obfusquées malveillantes dans des centaines de dépôts GitHub publics appartenant à des centaines de propriétaires uniques. Utilisez le tag #polinrider pour voir tous les rapports de menace liés à cette campagne, et rendez-vous à la fin de ce blog pour la liste des dépôts compromis, y compris ceux que nous recommandons de prioriser pour une action immédiate. Gardez à l'esprit que le tag est le meilleur moyen d'obtenir des données à jour.
La charge utile JavaScript est ajoutée à la fin des fichiers de configuration réels du projet — silencieusement, après le contenu légitime du fichier — ce qui la rend facile à manquer lors d'une revue de code informelle. Le vecteur d'infection principal semble être un paquet npm compromis qui s'exécute lors de l'installation ou de la construction et s'injecte dans les fichiers de configuration à la racine du projet. Pire encore, cet acteur de menace a utilisé la même technique pour créer également des paquets NPM malveillants.
Cette attaque a été extrêmement réussie, un projet open source compromis, Neutralinojs, ayant propagé le malware à des centaines de ses utilisateurs et contributeurs. Neutralinojs est un projet très populaire avec 8400 étoiles, 495 forks et des dizaines de contributeurs actifs. C'est la puissance de ce type d'attaque, car la menace ne se limite pas aux dépôts GitHub initiaux, mais s'étend à tous les autres projets qui utilisent cet open source.
L'équipe OpenSourceMalware a attribué cette campagne à la Corée du Nord, et l'acteur de menace PolinRider est un contributeur connu du groupe Lazarus avec des liens avec les campagnes "Contagious Interview" et "TasksJacker".
Cette campagne a considérablement augmenté depuis sa première publication. En date du 2026-04-11, l'équipe OSM a confirmé que 1 951 dépôts GitHub publics appartenant à 1 047 propriétaires uniques sont compromis. Cela représente une augmentation ×2,9 en cinq semaines depuis la date de publication originale (8 mars : 675 dépôts / 352 propriétaires).
| Métrique | 8 mars (initial) | 11 avril (dernier) | Δ |
|---|---|---|---|
| Dépôts uniques infectés | 675 | 1 951 | +1 276 |
| Propriétaires uniques affectés | 352 | 1 047 | +695 |
| — Utilisateurs individuels | 305 | ~930 | +625 |
| — Organisations | 47 | ~117 | +70 |
| Variantes d'obfusqueur distinctes observées | 1 (rmcej%otb%) | 2 (rmcej%otb% + Cot%3t=shtP) | +1 |
| Vecteurs d'injection distincts confirmés | 1 (fichier de configuration) | 4 (fichier de configuration, .vscode/tasks.json, faux fichier .woff2, dépendance npm malveillante) | +3 |
| Sous-domaines C2 distincts documentés | 1 (260120.vercel.app) | 6+ (voir Infrastructure C2) | +5 |
| Modèles de test à emporter armés connus | 0 | 2+ (ShoeVista, StakingGame) | +2 |

Lors d'une chasse de suivi commencée le 2026-04-10 et poursuivie jusqu'au 2026-04-11, l'équipe OSM a fait plusieurs découvertes majeures :
La campagne a plus que doublé en 5 semaines. L'énumération multi-moteurs via GitHub Code Search et Sourcegraph (avec un affinement au-delà de la limite de 1000 résultats de l'API — voir la méthodologie ci-dessous) a révélé 1 556 dépôts compromis uniques dans notre master v3 le premier jour. Une deuxième chasse le deuxième jour a ajouté 215 nouveaux dépôts via des pivots sur les noms de paquets npm, des pivots sur VS Code tasks.json / fournisseurs cloud, et le sous-domaine C2 nouvellement découvert default-configuration.vercel.app. Après dédoublonnage par rapport au corpus existant affected_repos.csv, la portée connue réelle est maintenant de 1 951 dépôts victimes uniques / 1 047 propriétaires uniques.
Une nouvelle variante a été observée. PolinRider a fait pivoter toutes les empreintes uniques de son obfusqueur tout en préservant l'architecture. La nouvelle variante utilise le marqueur de signature Cot%3t=shtP (était rmcej%otb%), la graine de mélange 1111436 (était 2857687), la graine secondaire 3896884 (était 2667686), et le nom de fonction de décodage MDy (était _$_1e42). Cette rotation semble être une réponse d'évasion à la règle YARA rmcej_otb_payload publiée. Les deux variantes sont actuellement actives dans la nature. Voir Nouvelle variante : Cot%3t=shtP ci-dessous.
L'acteur de menace réinfecte les victimes précédentes. Au moins un dépôt victime (HassanHabibTahir/testclient) contient des marqueurs des DEUX variantes dans différents fichiers, indiquant que les outils de l'acteur sont réexécutés sur des hôtes précédemment compromis et injectent le nouvel obfusqueur.
PolinRider et TasksJacker ont fusionné opérationnellement. Nous avons désormais la preuve directe que le même acteur de menace exécute à la fois l'injection de fichiers de configuration et le vecteur d'infection curl-to-shell via .vscode/tasks.json contre la même population de victimes. 22 des 101 victimes du script de propagation temp_auto_push.bat ont également des fichiers .vscode/tasks.json malveillants, et plusieurs projets de modèles de test à emporter / faux entretiens ont été identifiés — voir Modèles de test à emporter armés ci-dessous. OSM consolide les deux clusters sous #polinrider à l'avenir.
Deux projets de test à emporter armés identifiés : ShoeVista (une fausse évaluation e-commerce Tailwind qui embarque un tailwindcss-style-animate ^1.1.6 malveillant dans client/package.json) et StakingGame (un faux projet blockchain / automation VS Code identifié par l'UUID e9b53a7c-2342-4b15-b02d-bd8b8f6a03f9 dans tasks.json). Au moins 46 + 42 développeurs ont tenté ces tests et ont été compromis. Faisant partie du playbook de l'appât 'Contagious Interview'.
Cinq nouveaux sous-domaines C2 découverts utilisés dans les charges utiles curl | bash de .vscode/tasks.json, tous hébergés sur Vercel :
default-configuration.vercel.app (le plus utilisé, ~106 références de victimes)vscode-settings-bootstrap.vercel.appvscode-settings-config.vercel.appvscode-bootstrapper.vercel.appvscode-load-config.vercel.appTous suivent le modèle https://<sub>.vercel.app/settings/(mac|linux|win)?flag=<N>. Ajoutés à la section Infrastructure C2.