Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦
📦 npm
Not in CISA KEV
HIGH severity

CVE-2026-82392 — pnpm

HIGHFix: pnpm/pnpm@51300fd

CVE-2026-82392 is a high-severity (CVSS 7.1) Path Traversal vulnerability in pnpm. A fix is available for pnpm — see the affected versions and patch details below.

pnpm: Virtual store linker path traversal via unvalidated depPath name in lockfileToDepGraph

Also known asGHSA-c59q-g84q-2gj5
Published
Updated
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Oct 15, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-82392.

EPSS Exploitation Probability

via FIRST.org ↗
0.6%probability of exploitation in next 30 days
Lower Risk+0.22%
Lower risk than most CVEs48th percentile — riskier than 48% of all scored CVEsHighest risk
0.00%0.37%0.74%1.11%0.4%0.6%Sep 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

CVE-2026-82392 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 390,400 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

2 pkgs affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

407other npm packages depend on this — each one inherits the vulnerability until it's patched upstream
pnpmnpm
223.2Mdownloads / week

Description

Summary

The virtual store linker constructs package installation directories using path.join(modules, pkgName) where pkgName is extracted from lockfile packages keys via dp.parse(depPath).name without validation. A crafted pnpm-lock.yaml with traversal sequences in depPath keys (e.g., ../../../tmp/[email protected]) causes package content to be written to arbitrary filesystem paths during pnpm install.

This is an incomplete fix of GHSA-fr4h-3cph-29xv — the safeJoinModulesDir containment helper was applied to the hoisted linker and symlinkDependency but NOT to the virtual store linker's lockfileToDepGraph.ts:233.

Details

Root Cause

dp.parse() at pnpm11/deps/path/src/index.ts:135 extracts the package name as:

const name = dependencyPath.substring(0, sepIndex)

This is a raw substring operation with zero validation that name is a valid npm package name. A depPath of ../../../tmp/[email protected] yields name = '../../../tmp/pwned'.

Vulnerable Code Path

  1. pnpm-lock.yaml → lockfile.packages['../../../../../../../tmp/[email protected]'] (attacker-controlled lockfile key)
  2. nameVerFromPkgSnapshot(depPath, pkgSnapshot) at lockfile/utils/src/nameVerFromPkgSnapshot.ts:16 → calls dp.parse(depPath) → returns { name: '../../../../../../../tmp/pwned' }
  3. lockfileToDepGraph.ts:232 → modules = path.join(dirInVirtualStore, 'node_modules')
  4. lockfileToDepGraph.ts:233 → dir = path.join(modules, pkgName) → resolves to /tmp/pwned (ESCAPES virtual store)
  5. storeController.importPackage(depNode.dir, ...) → writes package content to the traversed path

Why Existing Defenses Don't Catch It

  • depPathToFilename() — replaces / with + for the dirInVirtualStore path, but pkgName comes SEPARATELY from dp.parse() and is NOT passed through this function
  • verifyLockfileResolutions() — validates dependency map keys (aliases) via isValidDependencyAlias(), but never validates the depPath keys themselves
  • Lockfile parser — yaml.load(lockfileRawContent) with no schema validation on packages keys
  • importPackage() — accepts targetDir and passes it directly to cafsStore.importPackage(targetDir, ...) with zero containment check
  • Integrity verification — requires a real fetchable package but does not validate the destination path

Escalation to RCE (non-default config)

When dangerouslyAllowAllBuilds: true is configured (or the traversal package name is in the explicit allowBuilds list), the same traversed path is used in the rebuild phase at after-install/src/index.ts:402,470. The attacker's postinstall script then executes with the victim's shell access. Under default config, allowBuild returns false for unknown packages, limiting impact to arbitrary file write.

Also Affected (PnP linker)

When nodeLinker: pnp is configured, lockfileToPackageRegistry() at lockfile/to-pnp/src/index.ts:105-110 uses the same unvalidated dp.parse().name in packageLocation construction, allowing the .pnp.cjs resolver map to point outside the virtual store. This is a lower-impact variant (PnP is not the default linker).

Impact

An attacker who can commit a crafted pnpm-lock.yaml to a repository (or supply one via a malicious package) can cause arbitrary file writes on the machine of any user who runs pnpm install. Written content is the actual package files from a real npm package (attacker controls which package and which destination).

Targets for arbitrary file write include:

  • .git/hooks/pre-commit — code execution on next git operation
  • ~/.local/bin/ — binary hijacking
  • Project source files — supply chain injection

Reproduction

Craft a pnpm-lock.yaml:

lockfileVersion: '9.0'
packages:
  ../../../../../../../tmp/[email protected]:
    resolution: {integrity: sha512-<real-package-integrity>}
    engines: {node: '>=14'}
snapshots:
  ../../../../../../../tmp/[email protected]: {}
importers:
  .:
    dependencies:
      legitimate-name:
        specifier: ^1.0.0
        version: ../../../../../../../tmp/[email protected]

Run pnpm install — package content is written to /tmp/pwned/ instead of the virtual store.

Recommended Fix

Apply safeJoinModulesDir (or equivalent validation) at:

  • lockfileToDepGraph.ts:233 — path.join(modules, pkgName)
  • after-install/src/index.ts:402 — path.join(pkgModulesDir(depPath), pkgInfo.name)
  • lockfile/to-pnp/src/index.ts:105-110 — PnP packageLocation

Alternatively, validate depPath keys during lockfile parsing to reject any that don't produce valid npm package names via dp.parse().

Relationship to GHSA-fr4h-3cph-29xv

GHSA-fr4h-3cph-29xv fixed the hoisted linker path (lockfileToHoistedDepGraph.ts:222) by adding safeJoinModulesDir. The same fix was NOT applied to the virtual store linker, which uses the identical dp.parse().name → path.join() pattern at lockfileToDepGraph.ts:233.

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
📦npmpnpmall versions10.34.5npm install pnpm@10.34.5
📦npmpnpm≥ 11.0.0&&< 11.11.011.11.0npm install pnpm@11.11.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for pnpm, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update pnpm to 10.34.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-82392 is resolved across your whole dependency graph.

  3. Workarounds

    Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant

This is an Important path traversal vulnerability in pnpm that allows an attacker to write arbitrary files outside the intended `node_modules` directory when a user executes `pnpm install` with a specially crafted `pnpm-lock.yaml`. While arbitrary file write is the default impact, this can escalate to arbitrary code…

Workaround published by Red Hat
To mitigate this vulnerability, avoid enabling `dangerouslyAllowAllBuilds` or adding untrusted package names to the `allowBuilds` configuration. By default, `pnpm` restricts lifecycle script execution for unknown packages, limiting the impact to arbitrary file writes. Users should exercise caution when installing packages from untrusted sources.
Source: Red Hat security advisory for CVE-2026-82392 (CC BY 4.0)

Frequently Asked Questions

## Summary The virtual store linker constructs package installation directories using `path.join(modules, pkgName)` where `pkgName` is extracted from lockfile `packages` keys via `dp.parse(depPath).name` without validation. A crafted `pnpm-lock.yaml` with traversal sequences in depPath keys (e.g., `../../../tmp/[email protected]`) causes package content to be written to arbitrary filesystem paths during `pnpm install`. This is an incomplete fix of GHSA-fr4h-3cph-29xv — the `safeJoinModulesDir` containment helper was applied to the hoisted linker and `symlinkDependency` but NOT to the virtual store
O3 Security · Impact-Aware SCA

Is CVE-2026-82392 in your dependencies?

Find it across npm, including transitive dependencies.

CVE-2026-82392: pnpm RCE — Fixed in 10.34.5