- Le compte npm atool a été compromis le 19 mai 2026, avec 637 versions malveillantes automatiquement publiées sur 317 paquets pendant environ 22 minutes
- La charge utile est un script Bun obfusqué de 498 Ko, utilisant la même structure de scanner et les mêmes expressions régulières que Mini Shai-Hulud employé lors de la compromission de SAP
- Les cibles d’exfiltration ont été étendues aux identifiants AWS, jetons Kubernetes, Vault, PAT GitHub, jetons npm, clés SSH et secrets locaux
- Dans les environnements CI, l’attaque échange l’OIDC de GitHub Actions contre un jeton de publication npm et abuse de la signature Sigstore ainsi que de l’injection de workflows malveillants
- La réponse nécessite de vérifier si une version compromise a été installée, de remplacer tous les identifiants potentiellement exposés, et de mettre en place le pinning du lockfile et des dépendances ainsi que des contrôles avant installation
Vue d’ensemble de l’attaque
- Le compte npm
atool(i@hust.cc) a été compromis le 19 mai 2026, et 637 versions malveillantes ont été publiées sur 317 paquets pendant environ 22 minutes - Ce compte maintenait 547 paquets, et l’attaquant a effectué deux incréments de version sur plus de 314 d’entre eux
- Parmi les paquets touchés figuraient
size-sensor(4,2 millions de téléchargements mensuels),echarts-for-react(3,8 millions),@antv/scale(2,2 millions),timeago.js(1,15 million), ainsi que de nombreux paquets du scope@antv - La charge utile est un script Bun obfusqué de 498 Ko, qui reprend la même structure de scanner, les mêmes expressions régulières d’identifiants et les mêmes motifs d’obfuscation que le toolkit Mini Shai-Hulud utilisé trois semaines plus tôt dans la compromission de SAP
- Les données volées sont soit commit dans un dépôt GitHub public sous forme d’objets Git, soit transmises via une requête HTTPS POST chiffrée en RSA+AES vers
t.m-kosche[.]com
Mode de déploiement et risque semver
- La première vague a publié environ 317 versions entre 01:39 et 01:56 UTC le 19 mai 2026, et la seconde a effectué environ 314 incréments de version sur les mêmes paquets entre 02:05 et 02:06 UTC
- La plupart des paquets, soit 309, ont reçu exactement 2 versions malveillantes, une par vague
- Quatre paquets —
size-sensor,echarts-for-react,jest-canvas-mock,jest-date-mock— ont reçu 3 versions, ce qui suggère leur utilisation pour les tests initiaux - L’attaquant n’a pas déplacé le dist-tag
latestsur la plupart des paquets, mais la résolution semver de npm sélectionne la version la plus élevée correspondant à la plage, indépendamment delatest - Par exemple, même si
latestdeecharts-for-reactreste sur3.0.6, un projet avec"echarts-for-react": "^3.0.6"peut être résolu vers la version malveillante3.2.7lors de la prochaine installation propre
Chaîne d’exécution et charge utile
- Toutes les versions compromises ajoutent dans
package.jsonun incrément de version et"preinstall": "bun run index.js" - Parmi les 637 versions malveillantes, 630 ajoutent aussi
@antv/setup: github:antvis/G2#<commit-sha>dansoptionalDependencies, afin de récupérer une seconde copie de la charge utile - Le hook
preinstalls’exécute avant l’installation des dépendances et nécessite l’environnement d’exécution Bun - Même si
preinstallest bloqué ou ignoré, le scriptpreparedu commit usurpant GitHub reste un second chemin d’exécution index.jsest un bundle Bun obfusqué de 498 Ko sur une seule ligne, avec les mêmes exigences Bun, la même obfuscation par variables hexadécimales, la même structure de scanner avec seuil de flush à 100 Ko, et le même ensemble d’expressions régulières d’identifiants que la charge utile Mini Shai-Hulud utilisée dans la compromission de SAP- La détection des environnements CI vérifie les variables d’environnement de plus de 20 plateformes, dont GitHub Actions, Jenkins, GitLab CI, CircleCI, Travis, Buildkite, Drone, TeamCity, AppVeyor, Bitbucket Pipelines, CodeBuild, Azure DevOps, Netlify et Vercel
Cibles de collecte d’identifiants
- La charge utile lit plus de 80 variables d’environnement aux noms chiffrés et analyse le contenu des fichiers via des expressions régulières
- Les principales cibles incluent les jetons GitHub, jetons npm, JWT GitHub Actions, clés AWS, clés Azure, chaînes de connexion de base de données, clés Stripe, clés SSH, authentification Docker, jetons Vault, jetons Kubernetes et identifiants intégrés dans les URL
- Le scanner de fichiers lit les emplacements standards d’identifiants dans le répertoire personnel, comme
.ssh,.aws/credentials,.npmrc,.docker/config.jsonet.kube/config - Il parcourt l’ordre complet de résolution des identifiants AWS, récupère les identifiants de rôle IAM depuis EC2 IMDSv2 et l’endpoint d’identifiants des conteneurs ECS, puis tente aussi d’accéder à AWS STS
GetCallerIdentityet à Secrets Manager - Pour Vault, il vérifie les fichiers de jeton ainsi que
VAULT_ADDR,VAULT_TOKEN,VAULT_ROLE, etc., puis tente l’énumération des secrets ainsi que l’authentification AWS et Kubernetes si des identifiants valides sont présents - Pour Kubernetes, il vérifie le jeton du service account et
KUBECONFIG, et si un socket Docker est présent, il tente d’énumérer les conteneurs de l’hôte et de s’échapper du conteneur
C2 et exfiltration de données
- L’API GitHub est utilisée comme C2, avec
GET /userpour valider les jetons GitHub volés etGET /user/orgspour énumérer les organisations - Les jetons disposant des permissions
repooupublic_reposont utilisés pour créer les dépôts d’exfiltration de l’attaquant - La description du dépôt créé utilise la chaîne inversée
niagA oG eW ereH :duluH-iahS, qui devient, dans le bon sens, « Shai-Hulud: Here We Go Again » - Les noms de dépôt combinent deux mots sur le thème de Dune et un nombre, comme
harkonnen-melange-742,fremen-sandworm-315ougesserit-navigator-508 - Les données exfiltrées sont stockées via la Git Data API dans l’ordre blob, tree, commit, puis mise à jour de ref
- Un expéditeur HTTPS distinct est configuré pour faire passer
hxxps://t.m-kosche[.]com/api/public/otel/v1/tracespour un endpoint d’ingestion de traces OTLP OpenTelemetry - La charge utile HTTPS chiffre un JSON gzip avec AES-256-GCM, puis encapsule la clé AES avec RSA-OAEP à l’aide d’une clé publique codée en dur
Abus de la CI/CD et de la chaîne de confiance
- Dans les dépôts GitHub accessibles avec les jetons volés, l’attaque collecte l’historique d’exécution des workflows, les artifacts, les noms des secrets, la liste des branches et la configuration Claude Code
- L’API GitHub ne donne pas accès aux valeurs des secrets, mais leurs noms révèlent quels types d’identifiants existent
- Le workflow malveillant est injecté dans
.github/workflows/codeql.yml, sous le nomRun Copilot, et se déclenche surpush - Le workflow place tous les secrets du dépôt dans une variable d’environnement JSON avec
VARIABLE_STORE: ${{ toJSON(secrets) }}, les enregistre dansformat-results.txt, puis les téléverse comme artifact - Une fois l’opération terminée, il télécharge l’archive zip de l’artifact, puis supprime l’exécution du workflow et réinitialise la ref de branche afin de réduire les traces de l’injection
- Dans les CI disposant de GitHub Actions OIDC, il tente d’échanger un jeton de publication npm via l’endpoint
https://registry.npmjs.org/-/npm/…; - La charge utile embarque une implémentation de signature Sigstore, incluant les formats Fulcio, Rekor et SLSA provenance, ce qui lui permet de produire des artifacts signés avec une identité CI compromise
Environnements de développement et agents de code IA infectés
- Le payload cible les environnements Claude Code, Codex et VS Code via une injection distante par l’API GitHub et une infection locale par écriture sur le système de fichiers
- Il commit
.vscode/tasks.json,.claude/index.js,.claude/settings.json,.claude/setup.mjs,.vscode/setup.mjsdans les dépôts accessibles avec les tokens dérobés .claude/settings.jsonenregistre un hookSessionStartafin d’exécuternode .claude/setup.mjsà chaque démarrage de session Claude Code.vscode/tasks.jsondéclenche l’exécution avec"runOn": "folderOpen"à l’ouverture du dossier du projetsetup.mjstélécharge Bun v1.3.14 depuis les releases officielles de GitHub, extrait le binaire puis exécute le payload- Le chemin d’infection locale copie le payload dans
~/.claude/package/index.jset~/.codex/package/index.js, puis scanne les fichiers de configuration existants du projet pour y injecter des hooks - Sur les Mac Apple Silicon, ce chemin d’infection locale est ignoré, alors qu’il s’exécute sur Linux, les Mac Intel et Windows
Persistance et C2 dead-drop via GitHub
- Un démon de persistance se faisant passer pour
kitty-monitorest installé comme service utilisateur systemd sur Linux et comme~/Library/LaunchAgents/com.user.kitty-monitor.plistsur macOS - L’installateur utilise
systemctl --user enable --nowetloginctl enable-lingerpour assurer la persistance même après la déconnexion - Le démon
cat.pyinterroge l’API GitHub Search toutes les heures et recherche les commits contenant le mot-cléfiredalazer - Le format du message de commit est
firedalazer <base64_url>.<base64_signature>, et après vérification de la signature RSA-PSS avec une clé publique RSA 4096 bits codée en dur, il exécute le code Python de l’URL - Un démon séparé
gh-token-monitorsonde les tokens GitHub volés toutes les 60 secondes, avec un TTL de 24 heures - Le scanner de mémoire de processus dumpe les régions mémoire lisibles des processus worker de GitHub Actions runner en utilisant
/proc/pid/maps+memsur Linux etReadProcessMemorysur Windows
Commits usurpant antvis/G2
- 630 des 637 versions malveillantes incluent une entrée
optionalDependenciespointant vers un commit spécifique du dépôtantvis/G2{ "optionalDependencies": { "@antv/setup": "github:antvis/G2#1916faa365f2788b6e193514872d51a242876569" } } - Quand npm résout une dépendance
github:, il récupère ce commit, cherchepackage.json, puis exécute les scripts de cycle de vie - Ce commit contient un
package.jsondéclarant@antv/setupet incluant un scriptprepare, ainsi qu’unindex.jsde 499 KB qui ré-obfusque le même payload Shai-Hulud - Le
&& exit 1du scriptpreparefait échouer l’optional dependency, mais npm ne traite pas cet échec comme fatal, donc l’installation continue - L’API Git montre trois SHA de commit différents poussés vers
antvis/G2, tous détachés de toute branche - Les trois commits partagent les mêmes métadonnées : author
huiyu.zjt <Alexzjt@users.noreply.github.com>, message de commitNew Package, aucun parent et aucune signature GPG - Sans droit d’écriture sur
antvis/G2, l’attaquant peut créer un orphan commit de payload dans un fork puis supprimer ce fork, laissant dans le namespace du dépôt parent un commit dont le SHA reste récupérable - Cette technique est du même type que le problème des commits usurpés dans GitHub Actions documenté par Chainguard, ici appliqué à la résolution des dépendances npm
github:
Indicateurs de compromission
- Les paquets publiés par
atool(i@hust.cc) entre le 19 mai 2026 01:44 et 02:06 UTC doivent être vérifiés - Le script
preinstallestbun run index.js - Le SHA256 du payload est
a68dd1e6a6e35ec3771e1f94fe796f55dfe65a2b94560516ff4ac189390dfa1c - Les commits usurpant
antvis/G2sont les suivants1916faa365f2788b6e193514872d51a242876569— 626 versions7cb42f57561c321ecb09b4552802ae0ac55b3a7a— 2 versionsdc3d62a2181beb9f326952a2d212900c94f2e13d— 1 version, garbage collected
- Les IoC réseau incluent
hxxps://t.m-kosche[.]com/api/public/otel/v1/traces, les requêtes de métadonnées EC2 vers169.254.169.254et les requêtes de métadonnées de conteneur ECS vers169.254.170.2 - Les IoC de dépôt incluent la branche
chore/add-codeql-static-analysis, le workflowRun Copilotet.github/workflows/codeql.ymlqui dumptoJSON(secrets)dansformat-results.txt - Les IoC d’environnement de développement incluent le hook
SessionStartdans.claude/settings.json,"runOn": "folderOpen"dans.vscode/tasks.json, ainsi que.claude/setup.mjset.vscode/setup.mjs - Les IoC de persistance incluent
kitty-monitor.service,com.user.kitty-monitor.plist,~/.local/bin/gh-token-monitor.sh,~/.local/share/kitty/cat.py,/var/tmp/.gh_update_state
Principaux paquets à vérifier
- Le tableau
compromised-packages.csvcontient deux colonnes, Package et Compromised Versions, et affiche 317 paquets selon le tableau - Il faut vérifier dans le lockfile la présence de ces paquets et des versions malveillantes publiées le 2026-05-19
- Principaux paquets
@antvet versions malveillantes@antv/g2:5.5.8,5.6.8@antv/g6:5.2.1,5.3.1@antv/g:6.4.1,6.5.1@antv/l7:2.26.10,2.27.10@antv/x6:3.2.7,3.3.7@antv/s2:2.8.1,2.9.1@antv/f2:5.15.0,5.16.0
- Paquets npm généraux et versions malveillantes
echarts-for-react:3.0.7,3.1.7,3.2.7size-sensor:1.0.4,1.1.4,1.2.4jest-canvas-mock:2.5.3,2.6.3,2.7.3jest-date-mock:1.0.11,1.1.11,1.2.11timeago.js:4.1.2,4.2.2timeago-react:3.1.7,3.2.7@lint-md/cli:2.1.0,2.2.0@lint-md/core:2.1.0,2.2.0@lint-md/parser:0.1.14,0.2.14
Réponse et défense
- Si une version compromise a été installée, il faut remplacer les jetons npm, les GitHub PAT, les clés AWS, les clés SSH, les identifiants cloud, les mots de passe de base de données, les jetons Vault, les jetons de service account Kubernetes et les secrets du gestionnaire de mots de passe local qui étaient accessibles depuis l’environnement de build
t.m-kosche[.]comdoit être bloqué au niveau du réseau et du DNS- Il faut vérifier si des dépôts publics non autorisés ont été créés sous des comptes GitHub disposant de jetons accessibles depuis l’environnement de build
- Il faut examiner les publications de paquets non autorisées et les journaux d’échange de jetons npm OIDC dans les pipelines CI
- Il faut vérifier les journaux de transparence Sigstore pour repérer d’éventuels artifacts signés créés avec une identité CI compromise
- Dans les projets Node.js locaux, il faut vérifier les hooks
.claude/settings.json, les tâches d’exécution automatique.vscode/tasks.json,.claude/setup.mjset.vscode/setup.mjs - Il faut supprimer le service utilisateur systemd
kitty-monitoret le LaunchAgentcom.user.kitty-monitor, puis vérifier la présence de~/.local/share/kitty/cat.py,/var/tmp/.gh_update_stateet~/.local/bin/gh-token-monitor.sh - Il faut épingler les dépendances ou utiliser un lockfile afin que la résolution des plages semver ne mène pas à une version malveillante
- Il faut auditer l’exposition du socket Docker et l’accès aux métadonnées EC2 dans les pipelines CI/CD, et envisager une limitation du hop limit d’IMDSv2
- Package Manager Guard (pmg) est un proxy d’installation open source qui compare les paquets à la threat intelligence avant l’exécution de
preinstall - dependency cooldown rejette les versions déployées dans une fenêtre de temps configurable, ce qui peut réduire les vagues de déploiement soudaines où une plage semver se résout vers une nouvelle release malveillante
- vet peut détecter des mises à jour anormales de paquets, comme un hook
preinstallinattendu, une forte hausse de taille ou un changement de maintainer, avant qu’elles n’atteignent les pipelines CI/CD - L’ampleur de l’impact — 547 paquets sous un seul compte et plus de 314 paquets militarisés en une seule session — met en évidence une faiblesse structurelle du modèle de confiance de npm
Références
- Shai-Hulud Goes Open Source: Static Analysis of the Framework — Datadog Security Labs
- The Shai-Hulud Code Drop — ReversingLabs
1 commentaires
Commentaires sur Hacker News
Il faut désormais désactiver par défaut les scripts de cycle de vie NPM
C’est en pratique une exécution de code arbitraire intégrée au nom de la commodité, et cela s’applique aussi aux dépendances transitives. Toutes les attaques de type ver NPM largement diffusées se sont propagées via ce réglage par défaut. Il ne faudrait pas qu’en l’activant une seule fois pour une commande donnée, toutes les dépendances transitives puissent exécuter des scripts de cycle de vie ; il faudrait obliger à l’indiquer explicitement pour chaque dépendance qui en a réellement besoin
L’écrasante majorité des paquets NPM ne dépend pas de tels scripts, donc si ce n’est pas déjà fait, mieux vaut les désactiver globalement
Cela dit, un paquet peut aussi exécuter les cochonneries qu’il veut dès sa première importation dans un programme
Dire qu’« il n’y a aucun moyen de l’empêcher », c’est quelque chose qu’on n’entend que pour le seul gestionnaire de paquets où ce genre d’incident se produit régulièrement
À partir d’un certain point, ne vaudrait-il pas mieux désactiver Dependabot et figer entièrement les paquets NPM, jusqu’aux versions mineures/correctifs, plutôt que de continuer à les mettre à jour ?
Surtout pour les paquets front-end, il semble aujourd’hui que les correctifs de sécurité significatifs soient moins fréquents que les attaques de supply chain
C’est triste à dire, mais y a-t-il une raison de ne pas transformer le front-end en BOM statique et de simplement faire confiance à NPM pour au moins respecter la contrainte « impossible de republier une ancienne version » ?
On peut prévoir une exception pour les versions qui corrigent une CVE connue
La situation devient de plus en plus folle. Personnellement, j’ai déjà supprimé node, python et tous les gestionnaires de paquets de ma machine, et je ne les utilise plus que dans des devcontainers ou des VM
Même si la communauté des développeurs finit par mettre en place une sécurité beaucoup plus renforcée, je crains qu’au moins d’ici un an, les capacités d’ingénierie sociale des modèles deviennent suffisamment bonnes pour qu’on reste malgré tout dans une partie perdue d’avance
Par exemple, l’effort investi dans le piratage de XZ était colossal et ne pouvait pas être accéléré, précisément parce qu’il reposait sur l’usure progressive du mainteneur existant au fil du temps. On peut générer et envoyer en quelques secondes les messages malveillants nécessaires, mais la vitesse des humains qui les lisent n’augmente pas ; et s’ils arrivent tous en même temps, cela éveillera au contraire les soupçons
Il y a aussi une limite à la crédibilité possible des entrées. On pourrait prendre n’importe quel message malveillant destiné au mainteneur de XZ et le rendre plus cruel, plus précis, mieux adapté à ses failles personnelles et à ses peurs, mais aurait-il été globalement plus efficace ? J’en doute, ou alors très légèrement tout au plus
Maintenant que Zed est passé en 1.0, j’aimerais migrer complètement, mais à ma connaissance son modèle de sécurité est tout ou rien. Soit on l’autorise à télécharger et installer librement des paquets NPM que je ne connais pas, soit on désactive toutes les fonctionnalités LSP
Et pourtant, on continue de voir passer ce genre de nouvelles
NPM ne pourrait-il pas mettre en place un programme où l’upload d’un paquet est automatiquement retardé d’environ 10 minutes, le temps de le distribuer à un écosystème d’entreprises tierces d’audit de code pour des vérifications automatisées ?
On pourrait publier un classement montrant quels auditeurs détectent les problèmes le plus vite et le plus fiablement, voire offrir des récompenses financières
Cette liste est incomplète. Au moins un autre paquet, l’extension VS Code nx-console, a aussi été infecté hier par ce ver, avec 2,2 millions de téléchargements
Si quelqu’un avec les accès et le réseau nécessaires lit ceci, cela vaut la peine d’examiner aussi sa chaîne de dépendances pour voir s’il y en a d’autres. Référence :
https://github.com/nrwl/nx-console/security/advisories/GHSA-...
PS : J’ai essayé de prévenir les gens sur HN juste après l’infection, mais malheureusement le post a à peine reçu de votes
À l’échelle de tout l’écosystème, TC39 devrait envisager d’ajouter à JS lui-même une meilleure bibliothèque standard. Cela réduirait le nombre de paquets d’une seule ligne
D’accord. Quand je travaillais autrefois avec Deno, l’un des meilleurs aspects était sa bibliothèque standard[0] et, de manière générale, un environnement de développement complet. Le fait que le runtime intègre un exécuteur de tests et une bibliothèque d’assertions paraît tellement évident
0 - https://docs.deno.com/runtime/reference/std/
node:test[0] etnode:assert/strict[1] par défaut.node --testpeut facilement remplacer Mocha, etnode:assert/strictest correct, même sichaiest parfois plus pratique. À cause de l’ergonomie de choses commeexpect. Le @std de Deno inclut une bibliothèque d’assertions de styleexpectLe problème, c’est qu’il y a trop d’exécuteurs de tests dans l’écosystème Node, et qu’une bonne partie d’entre eux ne se remplace pas aussi facilement que Mocha. Du coup, la migration vers le harnais de test et la bibliothèque d’assertions intégrés sera naturellement longue et pénible. Les gens aiment le caractère excessivement complexe de Jest et Vitest pour toutes sortes de raisons. Les grandes entreprises ont pensé que Karma était une bonne idée. Je ne comprends toujours pas pourquoi davantage de développeurs n’ont pas été horrifiés par l’idée : « Vous aimez V8 pour les tests unitaires ? Très bien, lançons alors une autre copie de V8 à l’intérieur de votre environnement V8 existant »
[0] https://nodejs.org/api/test.html
[1] https://nodejs.org/api/assert.html#strict-assertion-mode
Quelle bibliothèque standard de langage inclut un convertisseur du type « il y a 3 heures » ? C’est ce que fait timeago.js
slice.js ne fait qu’apporter l’indexation négative à la Python. TC39 a déjà fait en sorte que array.at() et array.slice() gèrent les indices négatifs
https://nodejs.org/api/
On dit que la charge utile vérifie la présence du socket Docker et, s’il existe, tente une évasion de conteneur par trois méthodes successives
Donc même si vous exécutez cela dans un devcontainer ou une VM, ce type de ver essaie déjà de s’en extraire
Il faut vérifier que vous utilisez un moteur de VM rootless. Par exemple podman plutôt que Docker
Cela me rappelle l’époque où des gens distribuaient des comptes Linux peu privilégiés en pensant que le noyau empêcherait les élévations de privilèges. Docker, c’est littéralement la même chose avec davantage d’étapes. Surtout aujourd’hui, où l’on a l’impression qu’une nouvelle faille locale d’élévation de privilèges dans le noyau sort toutes les cinq minutes
Podman est un peu mieux dans le sens où il ne donne pas root à l’attaquant, mais pourquoi donner un compte au départ ? Utilisez une vraie VM
Existe-t-il sous Linux un sandbox aussi complet que sur BSD ?
J’aimerais descendre de Mr Bones' Wild Ride, mais j’ai peur que ce genre de choses continue encore et encore. De ce que j’ai vu, une grande partie des stratégies de détection commerciales sont calibrées au niveau dépôt/appareil/développeur au moment où l’on charge ou utilise un paquet
Cela ressemble à la manière dont on traite les spams par e-mail ou les malwares classiques. Il y aura donc presque toujours des cibles suffisamment intéressantes pour que des acteurs malveillants continuent d’essayer. Mais contrairement à l’e-mail, les gestionnaires de paquets ont une autorité centralisée, et les problèmes hors bande risquent naturellement d’être renvoyés à la responsabilité du développeur
Vu de loin, sans être spécialiste, il faudrait peut-être s’éloigner de la culture des releases rapides et du versioning laxiste, pour se concentrer sur des versions du registre stables et inspectées en profondeur. Je peux me tromper à cause des effets de volume et d’échelle, mais le fait que les langages très mouvants soient plus souvent touchés reste suggestif
J’aimerais vraiment lire un article qui couvre de manière globale le paysage actuel
Le nom des montagnes russes dans ce film était Mr Bonestripper : https://www.youtube.com/watch?v=NEZEgd8GjJc
En fait, cela vient de Roller Coaster Tycoon 2 : https://knowyourmeme.com/memes/mr-bones-wild-ride
Pour reprendre la comparaison avec le spam, on s’est plus ou moins installé dans une situation où, dans presque tous les environnements de réseaux informatiques commerciaux et sociaux, on aspire les adresses e-mail, on fait accepter le spam par les utilisateurs et on lui donne une apparence de légitimité. Quelque chose de similaire risque fort d’arriver ici aussi. Ce sera peut-être une combinaison de logiciels de surveillance de licences à la Oracle et de gestion automatisée des dépendances, autrement dit une « solution » aux malwares de supply chain consistant à mettre d’autres malwares sur liste blanche