VYPR
High severity8.6GHSA Advisory· Published May 26, 2026· Updated May 26, 2026

yeoman-environment Vulnerable to Arbitrary Package Installation without User Confirmation

CVE-2026-42089

Description

Impact

yeoman-environment versions >= 2.9.0 and < 6.0.1 install missing local generator packages from caller-supplied package names without user confirmation. In downstream consumers that pass attacker-controlled project configuration into this path, this can result in arbitrary package installation and code execution during CLI bootstrap.

The vulnerable method is installLocalGenerators(), which calls repository.install() directly without prompting the user.

Patches

Upgrade to yeoman-environment 6.0.1, which adds an interactive confirmation prompt before installation (PR #753).

Workarounds

None.

Resources

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

yeoman-environment versions 2.9.0 to 6.0.0 allow arbitrary package installation without user confirmation via installLocalGenerators(), leading to potential code execution.

Vulnerability

yeoman-environment versions >= 2.9.0 and < 6.0.1 contain a vulnerability in the installLocalGenerators() method, which calls repository.install() directly without prompting the user for confirmation. This allows caller-supplied package names to be installed automatically during CLI bootstrap, even when those names originate from attacker-controlled project configuration [1][2].

Exploitation

An attacker who can control the project configuration (e.g., via a malicious package.json or Yeoman configuration file) can supply arbitrary package names. When a downstream consumer that uses yeoman-environment processes this configuration, the vulnerable code path triggers installation of those packages without any user interaction or confirmation. No authentication or special privileges are required beyond the ability to provide the configuration file [2].

Impact

Successful exploitation results in arbitrary package installation and code execution during the CLI bootstrap process. The attacker can execute arbitrary code with the privileges of the user running the Yeoman CLI, potentially leading to full compromise of the user's environment [2].

Mitigation

Upgrade to yeoman-environment version 6.0.1, which adds an interactive confirmation prompt before installing missing local generators (PR #753) [1][2]. No workarounds are available. This vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog as of the publication date.

AI Insight generated on May 26, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
78d2af7e6029

fix: ask before installing local packages. (#753)

https://github.com/yeoman/environmentMarcelo ShimaApr 9, 2026via body-scan-shorthand
2 files changed · +53 4
  • src/environment-full.ts+15 1 modified
    @@ -226,9 +226,23 @@ class FullEnvironment extends EnvironmentBase {
        * @param  {Object} packages - packages to install key(packageName): value(versionRange).
        * @return  {Boolean} - true if the install succeeded.
        */
    -  async installLocalGenerators(packages: Record<string, string | undefined>) {
    +  async installLocalGenerators(packages: Record<string, string | undefined>, forceInstall = false) {
         const entries = Object.entries(packages);
         const specs = entries.map(([packageName, version]) => `${packageName}${version ? `@${version}` : ''}`);
    +    if (forceInstall) {
    +      this.adapter.log.info(`Force install is enabled. Proceeding with installation.`);
    +    } else {
    +      const { aproveInstall } = await this.adapter.prompt({
    +        message: `The following packages need to be installed in the local repository: ${specs.join(', ')}. Do you want to proceed?`,
    +        type: 'confirm',
    +        name: 'aproveInstall',
    +        default: false,
    +      });
    +      if (!aproveInstall) {
    +        throw new Error(`Installation of ${specs.join(', ')} is declined by the user. Install manually and try again.`);
    +      }
    +    }
    +    this.adapter.log.info(`The following packages will be installed in the local repository: ${specs.join(', ')}.`);
         const installResult = await this.repository.install(specs);
         const failToInstall = installResult.find(result => !result.path);
         if (failToInstall) {
    
  • test/command.js+38 3 modified
    @@ -3,7 +3,8 @@ import path, { dirname } from 'node:path';
     import { fileURLToPath } from 'node:url';
     import { createRequire } from 'node:module';
     import { stub } from 'sinon';
    -import { beforeEach, describe, it } from 'esmocha';
    +import { beforeEach, describe, esmocha, expect, it } from 'esmocha';
    +import { TestAdapter } from 'yeoman-test';
     import { prepareCommand } from '../src/commands.ts';
     import Environment from '../src/index.ts';
     
    @@ -12,11 +13,45 @@ const __filename = fileURLToPath(import.meta.url);
     const __dirname = dirname(__filename);
     
     describe('environment (command)', () => {
    +  describe('#execute()', () => {
    +    let environment;
    +    let adapter;
    +
    +    beforeEach(async () => {
    +      adapter = new TestAdapter();
    +      environment = new Environment({ skipInstall: true, dryRun: true, adapter });
    +    });
    +
    +    describe('with non existing generator', () => {
    +      it('declining installation', async () => {
    +        adapter.addAnswers({
    +          aproveInstall: false,
    +        });
    +        environment.repository.install = esmocha.fn().mockReturnValue(Promise.resolve([]));
    +        await expect(environment.execute('commands:options')).rejects.toThrow(
    +          /Installation of generator-commands is declined by the user. Install manually and try again/,
    +        );
    +        expect(environment.repository.install).not.toHaveBeenCalled();
    +      });
    +
    +      it('approving installation', async () => {
    +        adapter.addAnswers({
    +          aproveInstall: true,
    +        });
    +        environment.repository.install = esmocha.fn().mockReturnValue(Promise.resolve([]));
    +        await expect(environment.execute('commands:options')).rejects.toThrow(
    +          /You don't seem to have a generator with the name “generator-commands” installed./,
    +        );
    +        expect(environment.repository.install).toHaveBeenCalledWith(['generator-commands']);
    +      });
    +    });
    +  });
    +
       describe('#execute() with options', () => {
         let environment;
     
         beforeEach(async () => {
    -      environment = new Environment([], { skipInstall: true, dryRun: true });
    +      environment = new Environment({ skipInstall: true, dryRun: true });
           environment.adapter.log = stub();
           await environment.register(path.join(__dirname, 'fixtures/generator-commands/generators/options'));
         });
    @@ -87,7 +122,7 @@ describe('environment (command)', () => {
         let environment;
     
         beforeEach(() => {
    -      environment = new Environment([], { skipInstall: true, dryRun: true });
    +      environment = new Environment({ skipInstall: true, dryRun: true });
           environment.adapter.log = stub();
           environment.register(path.join(__dirname, 'fixtures/generator-commands/generators/arguments'));
         });
    

Vulnerability mechanics

Root cause

"Missing user confirmation before installing local generator packages from caller-supplied package names."

Attack vector

An attacker who can control the project configuration (e.g., via a malicious `package.json` or Yeoman generator list) can supply arbitrary package names to `installLocalGenerators()`. Because the method previously called `repository.install()` without prompting the user [ref_id=1], the attacker's package would be fetched and installed from the npm registry during CLI bootstrap. If the installed package contains a postinstall script or is a malicious generator, the attacker achieves arbitrary code execution on the victim's machine.

Affected code

The vulnerable method is `installLocalGenerators()` in `src/environment-full.ts`. It calls `this.repository.install(specs)` directly without any user confirmation prompt, allowing arbitrary package installation from caller-supplied package names.

What the fix does

The patch adds an interactive confirmation prompt before installation in `installLocalGenerators()` [patch_id=2593860]. It introduces a `forceInstall` parameter; when `false` (the default), the method calls `this.adapter.prompt()` with a confirm dialog listing the packages to install. If the user declines, an error is thrown and `repository.install()` is never called. The test file was also updated to verify both the declining and approving paths, ensuring the prompt is enforced.

Preconditions

  • inputThe attacker must be able to supply or influence the package names passed to installLocalGenerators() (e.g., via a malicious project configuration or generator list).
  • networkThe victim must run a Yeoman CLI command that triggers the vulnerable code path.

Generated on May 26, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.