
Un assistant local d'installation de paquets faisait trop confiance aux noms de paquets fournis par l'appelant. Dans yeoman-environment, des generators manquants pouvaient être installés sans confirmation de l'utilisateur, transformant des métadonnées de projet contrôlées par l'attaquant en une voie d'installation de paquets et d'exécution de code.
Un assistant d'installation de paquets local faisait trop confiance aux noms de paquets fournis par l'appelant. Dans yeoman-environment, les générateurs manquants pouvaient être installés sans confirmation de l'utilisateur, transformant des métadonnées de projet contrôlées par un attaquant en un vecteur d'installation de paquets et d'exécution de code.
J'ai découvert ce problème en examinant generator-jhipster avec une simple question de sécurité en tête :
Des métadonnées de projet contrôlées par un attaquant peuvent-elles amener un outil de développement à récupérer et exécuter du code tiers avant que l'utilisateur ne l'ait explicitement demandé ?
Dans ce cas, la réponse était oui.
Ce qui ressemblait initialement à un problème JHipster s'est avéré avoir une cause racine plus profonde dans yeoman-environment.
Le comportement vulnérable se trouvait dans le flux d'installation locale de générateurs de Yeoman, où les paquets manquants fournis par l'appelant étaient installés automatiquement sans confirmation de l'utilisateur. Dans un consommateur aval qui transmettait des noms de paquets contrôlés par l'attaquant dans ce chemin, cela suffisait à créer une véritable chaîne d'installation de paquets et d'exécution de code.
Ce problème a donné lieu à CVE-2026-42089.
yeoman-environment : yeoman-environment sur GitHub
Paquet : yeoman-environment (npm)
CVE : CVE-2026-42089
Cela affectait yeoman-environment, la couche d'exécution derrière le flux de chargement et d'amorçage des générateurs de Yeoman. Le projet officiel le décrit comme le composant qui gère le cycle de vie et la découverte des générateurs, et au 26 juin 2026, la page du paquet npm indiquait 1 466 426 téléchargements hebdomadaires, ce qui en fait un paquet largement déployé dans l'écosystème des outils JavaScript.
configuration de projet contrôlée par l'attaquant -> noms de paquets de générateurs fournis par l'appelant -> yeoman-environment installe silencieusement les paquets manquants -> l'outil aval charge le code du générateur installé -> installation de paquets et exécution de code pendant l'amorçage de l'interface en ligne de commande
yeoman-environment est la couche d'exécution et de chargement des générateurs derrière les outils basés sur Yeoman.
Entre autres choses, il gère :
Cela signifie qu'il se trouve directement sur une frontière de confiance.
La question pertinente n'est pas de savoir si Yeoman est « simplement un outil local ».
La question pertinente est de savoir si une entrée non fiable peut influencer le comportement d'installation de paquets et de chargement de code.
Dans ce cas, c'était possible.
Je ne recherchais pas ici des corruption de mémoire ou des bogues de simple plantage.
La cible la plus pertinente était la surface d'extension et de résolution de paquets.
Tout système qui :
mérite un examen attentif.
C'est particulièrement vrai lorsque le consommateur aval peut dériver ces noms de paquets à partir de données locales au projet.
C'est exactement le genre d'endroit où une configuration ordinaire peut silencieusement devenir une frontière de sécurité.
C'était le bon endroit pour chercher.
J'ai d'abord reproduit le comportement via generator-jhipster.
Le chemin important était :
.yo-rc.json local au projet déclare un paquet de blueprintCela signifiait que même une commande anodine telle que :
jhipster --help
pouvait atteindre l'installation de paquets avant la fin de la commande demandée.
C'est une véritable défaillance de la frontière de confiance.
Le déclencheur aval a aidé à l'exposer, mais le comportement par défaut dangereux se trouvait dans Yeoman.
Le bogue était simple.
Dans yeoman-environment, la méthode vulnérable était :
async installLocalGenerators(packages) {
const entries = Object.entries(packages);
const specs = entries.map(([packageName, version]) => `${packageName}${version ? `@${version}` : ''}`);
const installResult = await this.repository.install(specs);
const failToInstall = installResult.find(result => !result.path);
if (failToInstall) {
throw new Error(`Fail to install ${failToInstall.pkgid}`);
}
await this.lookup({ packagePaths: installResult.map(result => result.path) });
return true;
}
Cette méthode installait directement les noms de paquets fournis par l'appelant via :
this.repository.install(specs)
sans demander d'abord confirmation à l'utilisateur.
C'est la vulnérabilité principale.
Parce que les noms de paquets n'ont pas besoin de provenir d'une source fiable.
Si un consommateur aval les dérive à partir de métadonnées de projet contrôlées par l'attaquant, alors la chaîne d'exploitation est simple :
Ce n'est pas seulement « l'installation de paquet a eu lieu ».
C'est une entrée non fiable qui franchit un puits d'installation de paquets sans frontière de consentement explicite.
La distinction importante est l'installation silencieuse à partir d'une entrée non fiable.
Il y a une vraie différence entre :
Cette distinction compte encore plus lorsque le paquet devient chargeable immédiatement après.
Le problème n'était pas que des générateurs tiers existent.
Le problème était que Yeoman traitait les noms de paquets fournis par l'appelant comme installables par défaut, sans confirmation de l'utilisateur.
Cela rend les hypothèses de confiance aval dangereuses matériellement pires.
C'est exactement pourquoi le correctif a ajouté une porte de confirmation.
J'ai utilisé deux niveaux de preuve car ils démontraient à la fois la cause racine et l'impact réel aval.
La première preuve utilisait generator-jhipster non modifié.
J'ai créé un projet avec un fichier .yo-rc.json racine qui référençait un paquet de blueprint non encore installé, puis j'ai exécuté :
jhipster --help
Cela a amené JHipster à transmettre le blueprint manquant dans le flux d'installation locale de générateurs de Yeoman avant la fin de l'aide.
Le résultat important était :
Cela a clairement établi la condition de déclenchement réelle.