
Un helper di installazione di pacchetti locale si fidava troppo dei nomi dei pacchetti forniti dal chiamante. In yeoman-environment, i generatori mancanti potevano essere installati senza conferma dell'utente, trasformando i metadati del progetto controllati dall'attaccante in un percorso di installazione di pacchetti ed esecuzione di codice.
Un helper locale per l'installazione di pacchetti si fidava troppo dei nomi di pacchetto forniti dal chiamante. In yeoman-environment, i generatori mancanti potevano essere installati senza conferma dell'utente, trasformando metadati di progetto controllati dall'attaccante in un percorso di installazione di pacchetti ed esecuzione di codice.
Ho trovato questo problema durante la revisione di generator-jhipster con una semplice domanda di sicurezza in mente:
I metadati di progetto controllati dall'attaccante possono far sì che uno strumento di sviluppo recuperi ed esegua codice di terze parti prima che l'utente lo richieda esplicitamente?
In questo caso, la risposta è stata sì.
Quello che inizialmente sembrava un problema di JHipster si è rivelato avere una causa principale più profonda in yeoman-environment.
Il comportamento vulnerabile si trovava nel flusso di installazione locale dei generatori di Yeoman, dove i pacchetti mancanti forniti dal chiamante venivano installati automaticamente senza conferma dell'utente. In un consumatore a valle che passava nomi di pacchetto controllati dall'attaccante in quel percorso, questo era sufficiente per creare una vera catena di installazione di pacchetti ed esecuzione di codice.
Questo problema è diventato CVE-2026-42089.
yeoman-environment: yeoman-environment su GitHub
Pacchetto: yeoman-environment (npm)
CVE: CVE-2026-42089
Questo ha interessato yeoman-environment, il livello runtime dietro il flusso di caricamento e avvio dei generatori di Yeoman. Il progetto ufficiale lo descrive come il componente che gestisce il ciclo di vita e la scoperta dei generatori e, al 26 giugno 2026, la pagina del pacchetto npm elencava 1.466.426 download settimanali, rendendolo un pacchetto ampiamente distribuito nell'ecosistema degli strumenti JavaScript.
configurazione di progetto controllata dall'attaccante -> nomi di generatori forniti dal chiamante -> yeoman-environment installa silenziosamente i pacchetti mancanti -> lo strumento a valle carica il codice del generatore installato -> installazione del pacchetto ed esecuzione del codice durante l'avvio della CLI
yeoman-environment è il runtime e il livello di caricamento dei generatori alla base degli strumenti basati su Yeoman.
Tra le altre cose, gestisce:
Ciò significa che si trova direttamente su un confine di fiducia.
La domanda rilevante non è se Yeoman sia "solo uno strumento locale".
La domanda rilevante è se l'input non fidato possa influenzare il comportamento di installazione dei pacchetti e caricamento del codice.
In questo caso, poteva.
Non stavo cercando vulnerabilità di corruzione della memoria o bug solo di crash.
L'obiettivo più forte era la superficie di estensione e risoluzione dei pacchetti.
Qualsiasi sistema che:
merita un esame attento.
Questo è particolarmente vero quando il consumatore a valle può derivare quei nomi di pacchetto da dati locali del progetto.
Questo è esattamente il tipo di posto in cui una configurazione ordinaria può tranquillamente diventare un confine di sicurezza.
Quello era il posto giusto dove guardare.
Ho prima riprodotto il comportamento attraverso generator-jhipster.
Il percorso importante era:
.yo-rc.json locale del progetto dichiara un pacchetto blueprintCiò significava che anche un comando benigno come:
jhipster --help
poteva raggiungere l'installazione del pacchetto prima che il comando richiesto fosse completato.
Questo è un vero fallimento del confine di fiducia.
Il trigger a valle ha aiutato a esporlo, ma il comportamento predefinito non sicuro era in Yeoman.
Il bug era semplice.
In yeoman-environment, il metodo vulnerabile era:
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;
}
Questo metodo installava direttamente i nomi di pacchetto forniti dal chiamante tramite:
this.repository.install(specs)
senza prima chiedere all'utente.
Questa è la vulnerabilità principale.
Perché i nomi di pacchetto non devono provenire da una fonte fidata.
Se un consumatore a valle li deriva da metadati di progetto controllati dall'attaccante, la catena di sfruttamento è semplice:
Non è solo "installazione del pacchetto avvenuta".
È input non fidato che attraversa un sink di installazione di pacchetti senza un confine di consenso esplicito.
La distinzione importante è l'installazione silenziosa da input non fidato.
C'è una reale differenza tra:
Quella distinzione conta ancora di più quando il pacchetto diventa caricabile immediatamente dopo.
Il problema non era che esistono generatori di terze parti.
Il problema era che Yeoman trattava i nomi di pacchetto forniti dal chiamante come installabili per impostazione predefinita senza conferma dell'utente.
Ciò rende le ipotesi di fiducia a valle non sicure materialmente peggiori.
Questo è esattamente il motivo per cui la correzione ha aggiunto una porta di conferma.
Ho usato due livelli di prova perché dimostravano sia la causa principale che l'impatto reale a valle.
La prima prova ha usato generator-jhipster non modificato.
Ho creato un progetto con un file .yo-rc.json principale che faceva riferimento a un pacchetto blueprint non ancora installato, quindi ho eseguito:
jhipster --help
Ciò ha fatto sì che JHipster passasse il blueprint mancante nel flusso di installazione locale del generatore di Yeoman prima che l'aiuto fosse completato.
Il risultato importante è stato:
Questo ha stabilito chiaramente la condizione di trigger reale.