Principaux enseignements
- En décembre 2025, un paquet publié dans un espace de noms adjacent à celui de Jackson a fourni Cobalt Strike à partir de Maven Central ; aucun CVE n'était concerné.
- Maven Central vérifie que l'utilisateur dispose bien du contrôle du domaine ou du compte d'hébergement d'un espace de noms, et non l'existence d'un lien quelconque avec le projet dont le nom est similaire.
- Les artefacts publiés via Maven Central comportent des signatures PGP, mais Maven ne les vérifie pas par défaut.
- En novembre 2025, un paquet npm compromis a été automatiquement transféré vers Maven Central via le système de mise en miroir mvnpm.
Depuis l’affaire Log4Shell, la plupart des discussions sur la chaîne d’approvisionnement Java ont porté sur un type de problème particulier : une vulnérabilité présente dans du code légitime. Puis, en décembre 2025, un autre problème est apparu. Une attaque par usurpation d’espace de noms a permis d’introduire un chargeur Cobalt Strike sur Maven Central, sous des coordonnées qui remplaçaient un seul segment des coordonnées réelles de Jackson.
Rien n'a été exploité. Aucune faille de sécurité n'était en cause. Quelqu'un a enregistré un espace de noms, publié un artefact, puis attendu que les mauvaises coordonnées soient copiées.
La sécurité de Maven Central ne se résume pas à la faille de vérification des signatures que la plupart des gens imaginent. Il s'agit également d'un problème d'espace de noms, et la plupart des outils Java ne détectent ni l'un ni l'autre.
Que s'est-il réellement passé avec le faux colis de Jackson ?
Le principe est suffisamment simple pour être expliqué en une seule phrase, et c'est précisément pour cela qu'il a fonctionné.
Jackson 2.x est publié sous com.fasterxml.jackson.core:jackson-databind. La société Aikido Security, qui a repéré le colis le 25 décembre, a répertorié l'artefact malveillant comme org.fasterxml.jackson.core avec le même jackson-databind artifactId, de sorte que la chaîne de coordonnées complète présentait un décalage de trois caractères. La dénomination par domaine inversé est censée empêcher cela, et à sa manière, elle a tenu ses promesses. Maven Central a confirmé que l’éditeur contrôlait un domaine correspondant à l’espace de noms. Ce domaine était fasterxml.org, enregistré via GoDaddy le 17 décembre 2025, huit jours avant l’analyse, et constituait une réplique quasi parfaite du véritable fasterxml.com. La vérification de la propriété a fonctionné correctement. Elle a simplement vérifié la mauvaise chose.
La charge utile n'était pas un simple coup rapide. Une fois désobfusquée, la classe s'est avérée être une fausse configuration automatique de Spring Boot, et les chercheurs qui l'ont examinée a mis au point une conception en plusieurs étapes: chaînes de configuration chiffrées en AES et déchiffrées à l'aide d'une clé codée en dur, un @Configuration classe annotée avec @ConditionalOnClass(ApplicationRunner.class) afin que Spring l'enregistre et exécute la charge utile une fois le contexte d'application chargé : un marqueur de persistance déguisé en fichier IntelliJ, ainsi qu'une identification de la plateforme avant l'envoi de tout trafic de commande et de contrôle. Les hôtes Windows ont téléchargé svchosts.exe, un « typosquat » du véritable svchost.exe processus. Les machines sous Linux et macOS ont reçu des fichiers binaires que la quasi-totalité des moteurs d'analyse de VirusTotal ont identifiés comme des balises Cobalt Strike, ce framework commercial de « red team » dont les versions divulguées sont largement utilisées par les auteurs de ransomware et les groupes APT.
Une fois le paquet signalé, Maven Central l’a retiré en environ quatre-vingt-dix minutes, ce qui constitue une réponse rapide pour un registre public. Cette rapidité n’aide toutefois pas les projets qui ont résolu le problème alors que le paquet était encore en ligne, et elle ne donne aucune indication sur la façon dont une version plus discrète de la même technique serait traitée. Une balise Cobalt Strike très visible a été détectée. Un programme conçu pour rester inactif et exfiltrer des données lentement pourrait rester en place bien plus longtemps.
Fonctionnement de l'usurpation d'espace de noms sur Maven Central
Maven identifie les dépendances à l'aide de trois coordonnées : groupId, artifactId et version.
La règle veut que le « groupId » corresponde à un domaine inversé contrôlé par l'éditeur, et Maven Central veille au respect de cette règle lors de l'enregistrement en exigeant la preuve du contrôle exercé sur ce domaine ou sur le compte d'hébergement de code qui y est associé. Cette vérification est bien réelle et fonctionne exactement comme prévu.
Tout simplement, cela ne signifie pas ce que les gens imaginent. Le fait de prouver que l'on contrôle un nom de domaine ne permet en rien de déterminer si l'éditeur a un quelconque lien avec le projet auquel l'espace de noms fait référence. Cela confirme simplement le contrôle d'un nom de domaine, et un nom de domaine similaire ne coûte que quelques dollars.
L'espace de noms réel de Jackson, à côté de trois modèles que n'importe qui pouvait enregistrer, dont aucun n'était celui utilisé ici.
| Motif à carreaux | Cela semble légitime parce que | Ce qui est réellement vérifié |
|---|---|---|
com.fasterxml.jackson.core |
C'est l'espace de noms réel | Gestion des domaines par FasterXML |
io.fasterxml.jackson |
Le domaine inversé « .io » est couramment utilisé pour les logiciels libres (OSS) | Le contrôle du nom de domaine revient à la personne qui l'a acheté |
com.fasterxml-jackson.core |
Un seul trait d'union : on le lit de la même manière au premier coup d'œil | Le contrôle du nom de domaine revient à la personne qui l'a acheté |
org.jackson.databind |
Correspond au nom du projet | Le contrôle du nom de domaine revient à la personne qui l'a acheté |
Le io.fasterxml.jackson, com.fasterxml-jackson.core, et org.jackson.databind Toutes ces variantes sont accessibles de manière légitime, sans qu'aucun élément ne soit compromis. L'incident Jackson reposait sur une version plus restreinte de ce même principe : il ne s'agissait pas d'un trait d'union ni d'un TLD différent, mais du remplacement d'un seul segment de premier niveau, passant de « com » à « org », associé à un domaine enregistré spécialement pour permettre à ce remplacement de passer la vérification.
Les coordonnées sont souvent copiées à partir de réponses sur Stack Overflow, d’articles de blog et d’extraits générés par l’IA, plutôt que saisies de mémoire, ce qui explique en partie pourquoi ce problème est plus difficile à repérer en Java qu’avec les paquets npm. Un développeur ayant installé axios une cinquantaine de fois remarquera immédiatement « axois ». Presque personne n’a mémorisé le « groupId » de Jackson, et encore moins de personnes remarqueraient un segment inversé dans une chaîne de quarante caractères qu’elles collent sans la relire.
Le fait de copier des coordonnées à partir d'une page de résultats de recherche plutôt que de la documentation propre au projet crée un risque supplémentaire de confusion entre les espaces de noms. Il vaut mieux abandonner cette habitude, quelle que soit l'issue de cet incident particulier.
La faille de sécurité de Maven Central que personne ne vérifie
Voici ce qui surprend les développeurs Java qui n'y ont pas prêté attention, et il s'agit d'un problème distinct de celui évoqué plus haut.
Maven Central n'accepte pas les versions dépourvues de signature PGP. Chaque artefact publié via Central est accompagné d'une .asc le fichier qui se trouve à côté, ainsi que les sommes de contrôle, et les exigences de publication sont plus strictes que celles de npm ou de PyPI. C'est là un véritable atout.
Par défaut, Maven ne vérifie pas ces signatures.
Exécuter mvn install dans le cadre d'un projet comportant deux cents dépendances transitives, Maven récupère deux cents fichiers JAR et compare les sommes de contrôle associées à chacun d'entre eux. Par défaut, une divergence donne lieu à un simple avertissement ; l'échec de la compilation pour l'une d'entre elles nécessite -C, ou un checksumPolicy d'échec dans le référentiel. Quoi qu'il en soit, le .asc Les fichiers situés à côté de ces fichiers JAR ne sont jamais modifiés, sauf si un plugin les sollicite.
La validation de la somme de contrôle et la vérification de la signature sont souvent considérées comme interchangeables, alors qu'elles ne le sont pas. Une somme de contrôle confirme que le fichier reçu correspond bien à celui mis à disposition par le référentiel. Une signature valide prouve que l'artefact a été signé avec une clé privée spécifique, et il faut un mappage de clés fiable pour associer cette clé à un éditeur digne de confiance. Maven effectue la première opération par défaut et ignore complètement la seconde.
Ce qui est important pour déterminer ce qui aurait pu aider ou non dans ce cas précis. L’attaquant contrôlait le site fasterxml.org et pouvait signer avec sa propre clé ; la vérification de la signature aurait donc également abouti pour le paquet malveillant. La vérification de la signature prouve qu’un artefact n’a pas été modifié depuis qu’il a été signé par le détenteur de cette clé. Elle ne permet toutefois pas de déterminer si cet éditeur est bien celui que le nom d’espace implique. Deux problèmes, deux solutions.
Gradle a une longueur d'avance sur Maven dans ce domaine, et la plupart des équipes ne l'ont toujours pas adopté.
./gradlew --write-verification-metadata sha256,pgp help
Cela permet de démarrer un verification-metadata.xml fichier issu de ce que Gradle résout, et c'est le processus de démarrage qui justifie ce ralentissement. Cette approche est délibérément optimiste. Les clés dont la vérification aboutit sont automatiquement ajoutées à la liste de confiance, les artefacts sans signature utilisable sont vérifiés à l’aide de sommes de contrôle, et tout élément déjà compromis dans votre arborescence est validé au passage. Lisez les sommes de contrôle et les clés de confiance générées avant de valider le fichier. Une fois cette base de référence vérifiée, Gradle fait échouer la compilation dès qu’un élément ne correspond plus, ce qui constitue un contrôle rigoureux sans pour autant alourdir la tâche sur un projet simple.
Maven n'a pas d'équivalent dans le noyau. La vérification passe par un plugin.
mvn org.simplify4u.plugins:pgpverify-maven-plugin:1.19.1:check
Cette fonctionnalité vérifie les signatures des dépendances et peut accepter une liste explicite de clés ; ainsi, seules les clés de signature que vous désignez sont considérées comme fiables. Elle fonctionne, mais ce n'est pas ce que tout le monde obtient par défaut.
Le problème « artefact contre source » est à l’origine de ces deux contrôles, car un fichier JAR est le résultat d’une compilation et rien ne garantit qu’il corresponde au dépôt de sources auquel un projet est lié. Un scanner analysant le binaire publié voit uniquement ce que l’éditeur a choisi d’y inclure, qu’il soit signé ou non. C’est en recompilant à partir de sources vérifiées que l’on obtient une trace indépendante du contenu d’un artefact, plutôt que de se fier au binaire fourni par l’éditeur ; et SecureChain for Java repose précisément sur ce principe.
MavenGate et le problème des coordonnées abandonnées
MavenGate, publié par des chercheurs d'Oversecured en janvier 2024, décrivait une autre méthode permettant d'aboutir à un résultat similaire, et celle-ci est sans doute la plus préoccupante car elle ne nécessite aucune usurpation d'identité.
Cette technique cible les dépendances abandonnées. Une bibliothèque publiée il y a plusieurs années sous com.oldcompany.util se retrouve dans des milliers d'arborescences de dépendances. L'entreprise fait faillite, le domaine expire, et personne ne s'en rend compte, car l'artefact continue d'être résolu sans problème depuis Maven Central.
Ce qui se passe ensuite est moins automatique qu’il n’y paraît. Lorsqu’aucun compte ne gère ce « groupId » dans un dépôt donné, toute personne détenant désormais le domaine peut le revendiquer à l’aide d’un enregistrement DNS de type TXT. Lorsque le « groupId » est déjà enregistré, en prendre le contrôle implique de convaincre l’équipe d’assistance de ce dépôt de transférer l’accès, et Oversecured a clairement indiqué ne disposer d’aucune information sur le fonctionnement de ces transferts. Une grande partie du risque provient également des projets s’étendant sur plusieurs dépôts, où une version malveillante introduite ailleurs dans la liste arrive tout de même sous des coordonnées auxquelles la compilation fait déjà confiance. Les projets utilisant des plages de versions, ou effectuant une mise à jour vers la version de l’attaquant, la récupèrent alors sans jamais voir de nom inconnu.
L’ampleur du problème est plus facile à cerner que son mécanisme. Oversecured a converti les « groupIds » de Maven Central en noms de domaine et a vérifié lesquels pouvaient être simplement achetés ; sur 26 163 domaines, 3 710 (soit 14,18 %) se sont avérés disponibles à l’achat. En élargissant cette analyse aux espaces de noms pris en charge par GitHub et aux dépôts privés que les chercheurs ont pu trouver, 18,18 % d’un ensemble de données comprenant 33 938 identifiants semblaient exposés.
Sonatype a remis en question la faisabilité de l’attaque, compte tenu des mécanismes d’automatisation en place, puis a désactivé les comptes liés à des domaines expirés, renforcé la vérification des espaces de noms et corrigé une régression dans la validation des clés publiques qui avait permis le passage d’artefacts signés avec des clés n’ayant jamais été publiées nulle part. Oversecured a répondu qu’aucun registre ne pouvait à lui seul remédier à ce problème, car l’attaque s’appuie sur des projets provenant simultanément de plusieurs dépôts publics, et que le mieux qu’un propriétaire de dépôt puisse faire est de refuser les revendications automatiques sur les espaces de noms déjà signalés comme vulnérables.
La politique habituelle de Maven Central consiste à garantir l'immuabilité des versions publiées ; ainsi, une version ne peut être modifiée ou retirée discrètement par son éditeur, et les retraits pour raisons de sécurité, comme celui concernant Jackson, constituent une exception très limitée. Cela est utile pour la reproductibilité. Cela signifie également que les dépendances abandonnées restent résolubles et continuent de figurer au cœur des arborescences de dépendances bien après que le domaine ou le compte associé à l'espace de noms a cessé d'être maintenu, apparaissant identiques à celles qui sont opérationnelles depuis l'intérieur d'un pom.xml.
Que deviennent ces bibliothèques lorsqu'un CVE est publié ? C'est une question à laquelle il n'existe pas de réponse satisfaisante. Il n'y a pas de version corrigée vers laquelle effectuer la mise à jour, et le fait d'intégrer une bibliothèque Java présentant un risque de sécurité dans votre propre référentiel signifie que votre équipe est désormais responsable de ses CVE, que vous ayez ou non prévu du personnel pour cela.
Comment un paquet npm compromis s'est retrouvé sur Maven Central
Ce que la plupart des équipes Java ne comprennent pas, c'est que cela peut se produire sans qu'aucun membre de l'équipe n'ait à utiliser npm.
En novembre 2025, la deuxième vague de la Le ver npm « Shai-Hulud » a atteint Maven Central grâce à la mise en miroir automatisée de mvnpm. mvnpm republie les paquets npm sous forme d’artefacts Maven afin que les projets web Java puissent récupérer les bibliothèques front-end via leur processus de compilation habituel, sans avoir recours à une chaîne d’outils JavaScript distincte. La mise en miroir est automatisée, et les nouvelles versions npm sont synchronisées dès leur publication ; c’est là tout l’intérêt de l’outil, mais c’est aussi précisément ainsi que le paquet compromis a pu passer entre les mailles du filet. Une version malveillante du paquet npm posthog-node Le package a été réintégré dans Maven Central sous le nom de org.mvnpm:posthog-node:4.18.1, portant le même setup_bun.js chargeur et bun_environment.js charge utile en tant que Campagne « Shai-Hulud » sur npm.
Socket a signalé l’artefact, et Maven Central a confirmé que la version compromise provenait du processus automatisé mvnpm, avant de purger toutes les copies en miroir le jour même. PostHog ne publie absolument rien sur Maven. Rien n’indique que le ver se soit propagé de manière autonome au sein de l’écosystème Maven ; seul cet artefact mis en miroir a été concerné. Cette distinction est importante pour déterminer dans quelle mesure il faut considérer cet incident comme un véritable schéma de chaîne d’approvisionnement Maven plutôt que comme un cas isolé. L’incident était bien réel et s’est produit de manière automatique : aucun responsable de maintenance Java n’a eu à republier quoi que ce soit pour qu’une version npm compromise soit mise à disposition des builds Java, mais le ver ne s’est pas comporté comme tel une fois arrivé à destination.
Cela montre toutefois que la synchronisation automatique déplace une limite de confiance sans que personne n’ait décidé de la déplacer. Une entreprise utilisant Java qui n’a jamais eu affaire à npm peut se retrouver à résoudre un paquet npm compromis, simplement parce qu’un service de passerelle l’a converti en fichier JAR à sa place.
| Chemin d'accès à une compilation Java | L'équipe doit utiliser npm | Visible dans le fichier pom.xml |
|---|---|---|
| Dépendance npm directe via une chaîne d'outils JS | Oui | Non |
| Artifact npm mis en miroir à partir d'un service passerelle | Non | Oui, sous la forme d'un fichier JAR standard |
| Dépendance Java transitive récupérant un artefact mis en miroir | Non | Uniquement sous dependency:tree |
Vérifiez directement le chemin transitif plutôt que de vous demander ce qui devrait s'y trouver. Découvrez ce que contient réellement votre arbre.
mvn dependency:tree -DoutputFile=deps.txt
Alors, lisez-le. Un service Spring de taille moyenne peut facilement résoudre plusieurs centaines d'artefacts à partir d'une vingtaine de dépendances déclarées. Les paquets en miroir apparaissent bien dans cette sortie, sous org.mvnpm coordonnées, ce qui constitue un véritable indice à condition qu'un membre de l'équipe sache que cet espace de noms correspond à du code npm reconditionné pour Maven.
Ce qu'il faut modifier dans votre build ce mois-ci
Commencez par l'outil de compilation que vous utilisez déjà, car ces deux approches ne demandent pas le même effort. Gradle permet de lancer rapidement la vérification des dépendances grâce à --write-verification-metadata sha256,pgp, il suffit ensuite de vérifier les hachages et les clés générés avant que le fichier ne soit validé. Maven ne disposant pas d'équivalent natif, cela implique d'ajouter un plugin et de verrouiller les versions dans pluginManagement, ce qui demande davantage de préparation, mais reste tout de même le travail d'une semaine, et non d'un trimestre.
Examinons ensuite la pratique qui a effectivement permis au paquet Jackson de passer entre les mailles du filet. Les coordonnées sont copiées là où elles se trouvent, sans être recoupées avec la documentation propre au projet, et il est plus facile de remédier à cela à l’aide d’une règle qu’avec un outil. Vérifiez tout `groupId` que votre équipe n’a jamais utilisé auparavant en le comparant aux coordonnées figurant dans le dépôt officiel ou la documentation du projet avant qu’il ne soit intégré à un pom.xml, en particulier tout contenu tiré d'un résultat de recherche ou d'un extrait généré par l'IA.
Les dépendances abandonnées nécessitent un autre type de prise de décision, et l’affaire « MavenGate » en est la raison. Un artefact sans version récente et sans responsable de maintenance actif est susceptible d’être repris, qu’il fasse ou non l’objet d’un CVE ouvert à l’heure actuelle, car le risque ne réside pas dans le code, mais dans le fait de savoir si quelqu’un contrôle encore le domaine ou le compte associé à cet espace de noms.
Un projet Gradle lancé ces deux dernières années peut intégrer la vérification en une journée. En revanche, pour une build Maven multimodule datant de dix ans, avec un fichier POM parent personnalisé et quarante plugins, c'est une autre histoire, et l'effort de mise en œuvre varie effectivement considérablement entre les deux cas.
Le rôle de SecureChain
Maven Central vérifie la propriété des espaces de noms lors de l'importation, et Maven compare les sommes de contrôle du référentiel lors de la compilation. Aucun élément du chemin par défaut ne permet de confirmer que le binaire que vous résolvez correspond bien à ce que le projet a réellement compilé. SecureChain for Java remplace ce chemin de résolution, en recompilant chaque paquet à partir d’une source vérifiée, en détectant tout comportement malveillant avant qu’il n’atteigne votre compilation, et en appliquant des correctifs en continu, y compris après la fin du support en amont. Votre workflow Maven ou Gradle existant reste inchangé : pointez-le vers TuxCare et continuez à compiler.
Découvrez ce que couvre SecureChain for OSS, ou abonnez-vous à la newsletter pour recevoir des analyses d'incidents comme celle-ci dès qu'elles sont publiées.
FAQ
Qu'est-ce que l'usurpation d'espace de noms sur Maven Central ?
Publier un artefact sous un `groupId` conçu pour ressembler à l'espace de noms d'un projet légitime. Maven Central vérifie que l'éditeur contrôle le domaine ou le compte d'hébergement correspondant, ce qui confirme le contrôle de cet espace de noms mais ne dit rien quant à un éventuel lien avec le projet imité.
Maven vérifie-t-il les signatures PGP ?
Pas par défaut. Maven Central exige des signatures PGP sur les artefacts publiés, et Maven compare les sommes de contrôle du référentiel, mais ne vérifie pas ces signatures ni leurs correspondances avec des clés de confiance par défaut. La vérification nécessite un plugin tel que pgpverify-maven-plugin.
Comment activer la vérification des dépendances dans Gradle ?
Exécuter ./gradlew --write-verification-metadata sha256,pgp help pour démarrer un verification-metadata.xml fichier, vérifiez les sommes de contrôle et les clés de confiance générées, puis validez cette configuration de référence. Par la suite, Gradle interrompra la compilation dès qu’un artefact présentera une somme de contrôle ou une signature qui ne correspond plus.
Qu'est-ce que MavenGate ?
Une technique de prise de contrôle, publiée par les chercheurs d'Oversecured en janvier 2024, qui cible les dépendances abandonnées. Quiconque acquiert le domaine ou le compte expiré associé à un ancien « groupId » peut être en mesure de revendiquer cet espace de noms dans un référentiel où personne ne le gère, ou tenter d'accéder à un enregistrement existant ; les projets utilisant des dépendances provenant de plusieurs référentiels peuvent alors accepter des artefacts malveillants sous des coordonnées familières.
Un paquet npm compromis peut-il avoir des répercussions sur un projet Java ?
Oui. Les services de passerelle qui republient automatiquement les paquets npm sous forme d'artefacts Maven peuvent introduire une version npm compromise dans Maven Central, où elle se traduit par une compilation Java sous la forme d'un fichier JAR ordinaire sous org.mvnpm coordonnées. Ces coordonnées désignent le pont, mais une équipe qui ne reconnaîtrait pas l'espace de noms traiterait l'artefact comme n'importe quelle autre dépendance. C'est exactement ce qui s'est produit lorsque Shai-Hulud 2.0 a été intégré à Maven Central via mvnpm en novembre 2025.
Comment savoir si ma compilation Java a intégré une bibliothèque Java malveillante ?
Exécuter mvn dependency:tree ou ./gradlew dependencies et vérifiez chaque `groupId` inconnu en vous référant à la documentation propre au projet en amont plutôt qu’à un résultat de recherche. Pour tout projet abandonné, considérez le risque de prise de contrôle comme indépendant du statut CVE. Cela revient toujours à ce type d’examen manuel, car la vérification de l’espace de noms effectuée par Maven Central établit le contrôle d’un domaine ou d’un compte d’hébergement plutôt qu’une affiliation à un projet portant un nom similaire, et Maven n’authentifie pas les signatures des dépendances par défaut.
Existe-t-il en Java un équivalent des scripts « postinstall » de npm ?
Cela ne concerne pas l'installation des dépendances, même si les builds Java continuent d'exécuter du code non fiable. Les plugins Maven s'exécutent au cours du cycle de vie de la compilation, les processeurs d'annotations s'exécutent au sein du compilateur, et les scripts de build Gradle sont des programmes exécutables plutôt que des fichiers de configuration. Le faux package Jackson utilisait une astuce similaire lors de l'exécution, permettant à Spring de détecter sa classe de configuration et de lancer la charge utile à sa place.



