pnpm, Package Manager Lockfile Trust Bypass, CAND-PNPM-063 (High) -DC-Jun2026-730

Listen to this Post

The vulnerability resides in pnpm’s automatic package-manager version switching mechanism. When a user runs `pnpm` directly in a repository that specifies a `packageManager` field (e.g., "packageManager": "[email protected]"), pnpm checks if the currently running version matches the wanted version. If not, it enters `switchCliVersion()` and attempts to download and execute the correct version.
To optimize this process, pnpm persists package-manager bootstrap metadata in the first YAML document of pnpm-lock.yaml. This “env lockfile” contains `packageManagerDependencies` entries for `pnpm` and @pnpm/exe, along with corresponding `packages` and `snapshots` sections that specify integrity hashes and tarball locations.
The vulnerable code path begins when `lockfile/fs/src/envLockfile.ts` reads the repository’s lockfile and performs only basic shape validation. Next, `pnpm/src/main.ts` invokes `switchCliVersion()` when it detects a version mismatch and the `onFail` policy is set to download. Inside switchCliVersion(), the committed env lockfile is loaded and passed to resolvePackageManagerIntegrities().
The critical flaw exists in installing/env-installer/src/resolvePackageManagerIntegrities.ts: this function treats `packageManagerDependencies` as already resolved if the `pnpm` and `@pnpm/exe` versions match the requested ones. It does not verify the integrity or authenticity of the package metadata—it merely checks version strings. Consequently, a malicious repository can commit a lockfile containing arbitrary `packages` entries with attacker-chosen integrity hashes and tarball URLs.
When `switchCliVersion()` proceeds, it hands the env lockfile to `installPnpmToStore()` (via engine/pm/commands/src/self-updater/installPnpm.ts), which converts the `snapshots` and `packages` sections into a lockfile used by headlessInstall(). This installs the package manager from the attacker-controlled metadata without any fresh resolution from trusted registries. Finally, `switchCliVersion()` executes the installed binary via spawn.sync(), granting the attacker arbitrary code execution with the victim’s privileges.
The patch forces `switchCliVersion()` to call `resolvePackageManagerIntegrities()` with force: true, which bypasses the version-only fast path and re-resolves the package-manager entries through trusted registries before installation or execution. The helper function itself retains the fast path for non-execution callers, but the execution boundary is now secured.

DailyCVE Form:

Platform: pnpm (npm)
Version: main (before patch)
Vulnerability: Lockfile trust bypass
Severity: High (CVSS 8.8)
date: 2026-06-09

Prediction: 2026-06-16

What Undercode Say:

Analytics and validation commands from the patch branch:

TypeScript builds
./node_modules/.bin/tsgo --build installing/env-installer/tsconfig.json
./node_modules/.bin/tsgo --build pnpm/tsconfig.json
Focused Jest regression tests
PNPM_REGISTRY_MOCK_PORT=7799 NODE_OPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../node_modules/.bin/jest src/switchCliVersion.test.ts -t "re-resolved package-manager lockfile" --runInBand
PNPM_REGISTRY_MOCK_PORT=7799 NODE_OPTIONS="--experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169" ../node_modules/.bin/jest src/switchCliVersion.test.ts src/syncEnvLockfile.test.ts --runInBand
ESLint checks
./node_modules/.bin/eslint installing/env-installer/src/resolvePackageManagerIntegrities.ts pnpm/src/switchCliVersion.ts pnpm/src/switchCliVersion.test.ts
Whitespace check
git diff --check

PoC snippet for constructing a poisoned env lockfile:

{
"importers": {
".": {
"configDependencies": {},
"packageManagerDependencies": {
"@pnpm/exe": { "specifier": "9.3.0", "version": "9.3.0" },
"pnpm": { "specifier": "9.3.0", "version": "9.3.0" }
}
}
},
"lockfileVersion": "9.0",
"packages": {
"/[email protected]": {
"resolution": {
"integrity": "sha512-poisoned"
}
}
},
"snapshots": {
"/[email protected]": {}
}
}

Exploit:

  1. Attacker creates a malicious repository with a `package.json` specifying "packageManager": "[email protected]".
  2. Attacker commits a `pnpm-lock.yaml` containing a crafted env lockfile with matching version strings but poisoned `packages` and `snapshots` entries (e.g., a tarball from an attacker-controlled registry or a manipulated integrity hash).
  3. Victim clones the repository and runs `pnpm` directly (any command, e.g., pnpm install).
  4. pnpm detects version mismatch, enters switchCliVersion(), reads the committed env lockfile, and skips fresh resolution because versions match.
  5. pnpm installs the package manager using the poisoned metadata and executes the resulting binary via spawn.sync().
  6. Attacker gains arbitrary code execution in the victim’s environment with the victim’s user privileges.

Protection:

  • Patch: Apply the fix that introduces `force: true` in switchCliVersion(), forcing re-resolution through trusted registries before installation.
  • Workaround: Disable automatic package-manager switching by setting `onFail` to `error` or `ignore` in the repository configuration (if feasible).
  • Mitigation: Use `–package-manager-strict` or similar flags to enforce fresh resolution; avoid running `pnpm` in untrusted repositories without review.
  • Verification: After patching, ensure that `resolvePackageManagerIntegrities()` is called with `force: true` when the env lockfile already contains matching versions, and that the installer receives the refreshed lockfile rather than the committed one.

Impact:

  • Confidentiality: Attacker can read local secrets, environment variables, and source code.
  • Integrity: Attacker can alter project files, inject malicious dependencies, or modify build outputs.
  • Availability: Attacker can disrupt the development or CI pipeline, delete files, or install backdoors.
  • Scope: All developers and CI systems using pnpm with auto-switching enabled are vulnerable when cloning malicious repositories. The attack requires no user privileges beyond running `pnpm` and no network manipulation—the malicious lockfile is delivered through standard supply-chain channels (e.g., GitHub, npm). CVSS score remains 8.8 (High) for unpatched versions.

🎯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

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top