CVE-2026-82392 Overview
CVE-2026-82392 is a path traversal vulnerability [CWE-22] in pnpm, a widely used JavaScript package manager. Versions prior to 10.34.5 and versions 11.0.0 through 11.11.0 parse attacker-controlled package names from pnpm-lock.yaml without validation. The unsanitized name flows into path.join(modules, pkgName) and storeController.importPackage, allowing package contents to be written outside node_modules when a user runs pnpm install. When dangerouslyAllowAllBuilds or a matching allowBuilds entry permits lifecycle scripts, the escaped package can execute arbitrary code with the invoking user's privileges.
Critical Impact
A malicious lockfile can drop files anywhere the user has write access and, if lifecycle scripts are allowed, achieve code execution during a routine pnpm install.
Affected Products
- pnpm versions prior to 10.34.5
- pnpm versions 11.0.0 up to and including 11.10.x
- Projects consuming untrusted pnpm-lock.yaml files via pnpm install
Discovery Timeline
- 2026-08-31 - CVE-2026-82392 published to NVD
- 2026-09-01 - Last updated in NVD database
Technical Details for CVE-2026-82392
Vulnerability Analysis
pnpm resolves each dependency entry in pnpm-lock.yaml by calling dp.parse(depPath).name to extract the package name. The parsed value is trusted and consumed directly by downstream file-system operations in deps/graph-builder/src/lockfileToDepGraph.ts and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts. Because the name originates from lockfile keys that an attacker controls, a crafted entry can contain traversal sequences such as ../ or absolute path fragments.
The unvalidated name reaches three sinks: path.join(modules, pkgName), storeController.importPackage, and the Plug'n'Play writer in pnpm11/lockfile/to-pnp/src/index.ts. Each sink resolves the path relative to the virtual store or node_modules without confining the result. A supply-chain attacker who can influence a repository's committed lockfile can therefore stage files at arbitrary locations on the developer's or CI runner's filesystem.
Root Cause
The root cause is missing containment on parsed dependency names. pnpm assumed pnpm-lock.yaml keys were well-formed npm package identifiers, but the parser does not reject names that decode into relative-path components. The fix introduces a safeJoinModulesDir helper and a new verify_lockfile_dependency_names() verification pass that rejects names attempting to escape the modules directory.
Attack Vector
Exploitation requires the victim to run pnpm install against a repository containing a malicious pnpm-lock.yaml. The attack is network-adjacent through typical supply-chain vectors: a poisoned public package, a compromised fork, or a pull request that alters the lockfile. Code execution follows only when lifecycle scripts are permitted through dangerouslyAllowAllBuilds or a matching allowBuilds allowlist entry that covers the attacker-controlled name.
// Patch excerpt: deps/graph-builder/src/lockfileToDepGraph.ts
type FetchResponse,
type StoreController,
} from '@pnpm/store-controller-types'
+import { safeJoinModulesDir } from '@pnpm/symlink-dependency'
import * as dp from '@pnpm/dependency-path'
import pathExists from 'path-exists'
import equals from 'ramda/src/equals'
Source: GitHub Commit 78e29fe
// Patch excerpt: pacquet/crates/package-manager/src/create_symlink_layout.rs
-use crate::{SkippedSnapshots, SymlinkPackageError, VirtualStoreLayout, symlink_package};
+use crate::{
+ SkippedSnapshots, SymlinkPackageError, VirtualStoreLayout,
+ safe_join_modules_dir::safe_join_modules_dir, symlink_package,
+};
use pacquet_lockfile::{PkgName, SnapshotDepRef};
use std::{collections::HashMap, path::Path};
Source: GitHub Commit 51300fd
Detection Methods for CVE-2026-82392
Indicators of Compromise
- pnpm-lock.yaml files containing package keys with ../, ..\, absolute paths, or URL-encoded traversal sequences in the name portion.
- Files created outside the project's node_modules directory during or immediately after a pnpm install run.
- Unexpected writes to user profile directories, CI workspace roots, or shell startup files by the pnpm or node process.
- Lifecycle script execution originating from a package name that does not match a known registry package.
Detection Strategies
- Scan repositories and pull requests for pnpm-lock.yaml entries whose top-level keys fail a strict npm package-name regex.
- Compare pre- and post-install filesystem snapshots on CI runners to flag writes outside the project workspace.
- Alert on pnpm install invocations that spawn child processes writing to paths outside node_modules.
- Inventory pnpm versions across developer endpoints and build agents; flag any version below 10.34.5 or between 11.0.0 and 11.10.x.
Monitoring Recommendations
- Enable EDR file-write telemetry on developer workstations and CI hosts, focusing on process ancestry rooted in pnpm or node.
- Log and review changes to pnpm-lock.yaml in code review, especially in pull requests from forks or first-time contributors.
- Monitor for the addition of dangerouslyAllowAllBuilds: true or new allowBuilds entries in .npmrc or package.json.
How to Mitigate CVE-2026-82392
Immediate Actions Required
- Upgrade pnpm to 10.34.5 on the v10 branch or 11.11.0 on the v11 branch across all developer machines and CI runners.
- Audit recent pnpm-lock.yaml changes for entries containing traversal characters or otherwise malformed package names.
- Disable dangerouslyAllowAllBuilds and review every entry in allowBuilds to ensure only trusted packages can run lifecycle scripts.
- Rotate any credentials that were accessible from a workstation or CI job that ran pnpm install against an untrusted lockfile.
Patch Information
The issue is fixed in pnpm 10.34.5 and 11.11.0. The fix, delivered in PR #12872 and backported in PR #12890, introduces safeJoinModulesDir containment for TypeScript code paths and safe_join_modules_dir plus verify_lockfile_dependency_names() in the Rust pacquet crates. Full details are in GHSA-c59q-g84q-2gj5.
Workarounds
- Run pnpm install --ignore-scripts when working with any lockfile from an untrusted source until upgrading is complete.
- Execute pnpm install inside an ephemeral container or sandbox with no access to sensitive host paths or credentials.
- Require signed commits and enforce lockfile review policies so that untrusted contributors cannot modify pnpm-lock.yaml without approval.
# Upgrade pnpm to a fixed release
npm install -g pnpm@10.34.5 # v10 branch
# or
npm install -g pnpm@11.11.0 # v11 branch
# Verify installed version
pnpm --version
# Safer install when reviewing untrusted lockfiles
pnpm install --ignore-scripts
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
