{"id":"CVE-2026-82393","aliases":["EUVD-2026-68883","GHSA-vq4v-j7r6-jq4m"],"status":"published","title":"pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install","description":"pnpm is a package manager. Prior to 10.34.5 and 11.11.0, pnpm accepts a scoped path traversal in a tarball dependency's package.json manifest name because pnpm11/resolving/npm-resolver/src/pickPackage.ts rejects slash characters only for unscoped names. During pnpm install, the unvalidated name reaches raw path joins in pnpm11/installing/deps-resolver/src/resolvePeers.ts, pnpm11/installing/deps-resolver/src/index.ts, and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts, causing package extraction outside node_modules and allowing attacker-controlled files to overwrite arbitrary filesystem paths even when --ignore-scripts is used. The overwrite can replace shell startup files, Git hooks, or installed package code and lead to code execution. This issue is fixed in versions 10.34.5, and 11.11.0.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.00626,"percentile":0.50542,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-22","CWE-73","CWE-94"],"published":"2026-08-31T21:12:09Z","modified":"2026-11-03T22:23:37Z","fixes":[{"ecosystem":"npm","package":"pnpm","fixed_in":["10.34.5","11.11.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"pnpm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"10.34.5"}]}]},{"source":"ghsa","ecosystem":"npm","package":"pnpm","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"11.0.0"},{"fixed":"11.11.0"}]}]},{"source":"osv","ecosystem":"npm","package":"pnpm","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"10.34.5"}]}]},{"source":"osv","ecosystem":"npm","package":"pnpm","ranges":[{"type":"SEMVER","events":[{"introduced":"11.0.0"},{"fixed":"11.11.0"}]}]}],"products":[{"vendor":"pnpm","product":"pnpm"}],"references":[{"url":"https://github.com/pnpm/pnpm/security/advisories/GHSA-vq4v-j7r6-jq4m","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/pnpm/pnpm/pull/12872","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pnpm/pnpm/pull/12890","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pnpm/pnpm/commit/51300fd41c5e4c8f47635108e373cc3d1f324fa7","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pnpm/pnpm/commit/78e29fe5583a1e5d69ea05e414eff310f78d5ed9","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/pnpm/pnpm/releases/tag/v10.34.5","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/pnpm/pnpm/releases/tag/v11.11.0","tags":["x_refsource_MISC","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-82393","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-vq4v-j7r6-jq4m"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/82xxx/CVE-2026-82393.json","tags":["advisory"]},{"url":"https://github.com/pnpm/pnpm","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-82393","title":"pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install","description":"pnpm is a package manager. Prior to 10.34.5 and 11.11.0, pnpm accepts a scoped path traversal in a tarball dependency's package.json manifest name because pnpm11/resolving/npm-resolver/src/pickPackage.ts rejects slash characters only for unscoped names. During pnpm install, the unvalidated name reaches raw path joins in pnpm11/installing/deps-resolver/src/resolvePeers.ts, pnpm11/installing/deps-resolver/src/index.ts, and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts, causing package extraction outside node_modules and allowing attacker-controlled files to overwrite arbitrary filesystem paths even when --ignore-scripts is used. The overwrite can replace shell startup files, Git hooks, or installed package code and lead to code execution. This issue is fixed in versions 10.34.5, and 11.11.0.","status":"published","published":"2026-08-31T21:12:09.196Z","modified":"2026-11-03T22:23:37.318Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-22","CWE-73","CWE-94"],"updated_at":"2026-11-03T23:33:09.822755Z"}],"euvd":[{"id":"EUVD-2026-68883","description":"pnpm is a package manager. Prior to 10.34.5 and 11.11.0, pnpm accepts a scoped path traversal in a tarball dependency's package.json manifest name because pnpm11/resolving/npm-resolver/src/pickPackage.ts rejects slash characters only for unscoped names. During pnpm install, the unvalidated name reaches raw path joins in pnpm11/installing/deps-resolver/src/resolvePeers.ts, pnpm11/installing/deps-resolver/src/index.ts, and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts, causing package extraction outside node_modules and allowing attacker-controlled files to overwrite arbitrary filesystem paths even when --ignore-scripts is used. The overwrite can replace shell startup files, Git hooks, or installed package code and lead to code execution. This issue is fixed in versions 10.34.5, and 11.11.0.","status":"published","published":"2026-08-31T21:12:09Z","modified":"2026-11-03T22:23:37Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-03T23:01:34.013136Z"}],"ghsa":[{"id":"GHSA-vq4v-j7r6-jq4m","title":"pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install","description":"## Summary\nWhen resolving a package, pnpm uses the resolved **manifest `name`** as a raw path segment for the isolated-linker import target. A tarball dependency whose `package.json` `name` is a scoped path traversal (`@x/../../…/\u003cabs path\u003e`) is therefore extracted **outside `node_modules`**, to an attacker-chosen absolute path, and can **overwrite existing files** there. Attacker controls the destination, filenames, and contents → arbitrary file write → **code execution** (e.g. `~/.zshrc`, `.git/hooks/pre-commit`, another package's code). Occurs during `pnpm install` **even with `--ignore-scripts`** (no lifecycle scripts run), defeating that safety.\n\nSame class as the just-patched **GHSA-hwx4** (transitive-dependency *alias* traversal) and **GHSA-v23m** (`stage download` manifest name/version traversal), in a sink their fixes did not cover: the isolated-linker import target keyed by the resolved **name**.\n\n## Root cause\n- The isolated-linker import target is built with a raw `path.join(modules, \u003cresolved name\u003e)` in `installing/deps-resolver/src/resolvePeers.ts:706`, `installing/deps-resolver/src/index.ts:614`, and `deps/graph-builder/src/lockfileToDepGraph.ts:233` — **without** the `safeJoinModulesDir` guard used on the symlink/hoisted/bin paths (`installing/deps-restorer/src/lockfileToHoistedDepGraph.ts:222`). The store location is `node_modules/.pnpm/\u003cid\u003e/node_modules/\u003cname\u003e`, so a traversal `\u003cname\u003e` escapes.\n- The only resolve-time name gate (`resolving/npm-resolver/src/pickPackage.ts:753`) rejects only *unscoped* names containing `/`, so a **scoped** `@x/../..` passes.\n\n## Steps to reproduce\nSelf-contained PoC (real `pnpm@11.9.0`; loopback tarball server; escape target is a throwaway temp dir):\n```\nnpm i pnpm@11.9.0\n# host a tarball whose package.json name = \"@x/\"+\"../\".repeat(25)+\"\u003cabs\u003e/OUTSIDE\"; victim depends on the http URL\npnpm install --ignore-scripts\n```\nConfirmed output (`repro/poc.mjs`, exit 0):\n```\nescape dir is outside the project        : true\nnew file implanted outside node_modules  : true\npre-existing file OVERWRITTEN            : true\n*** CONFIRMED: a tarball dependency wrote \u0026 overwrote files OUTSIDE the project during `pnpm install --ignore-scripts` ***\n```\n\n## Remediation\nRoute the isolated-linker import-target joins (`resolvePeers.ts:706`, `deps-resolver/index.ts:614`, `lockfileToDepGraph.ts:233`) through `safeJoinModulesDir` (as the hoisted linker already does), and/or enforce `validate-npm-package-name` on the resolved manifest name (close the scoped-name gap at `pickPackage.ts:753`) so the import target rejects a traversal name and re-asserts containment before any write.","status":"published","published":"2026-09-02T14:36:59Z","modified":"2026-09-02T14:37:00Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-22","CWE-73","CWE-94"],"updated_at":"2026-11-02T14:41:10.121131Z"}],"nvd":[{"id":"CVE-2026-82393","description":"pnpm is a package manager. Prior to 10.34.5 and 11.11.0, pnpm accepts a scoped path traversal in a tarball dependency's package.json manifest name because pnpm11/resolving/npm-resolver/src/pickPackage.ts rejects slash characters only for unscoped names. During pnpm install, the unvalidated name reaches raw path joins in pnpm11/installing/deps-resolver/src/resolvePeers.ts, pnpm11/installing/deps-resolver/src/index.ts, and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts, causing package extraction outside node_modules and allowing attacker-controlled files to overwrite arbitrary filesystem paths even when --ignore-scripts is used. The overwrite can replace shell startup files, Git hooks, or installed package code and lead to code execution. This issue is fixed in versions 10.34.5, and 11.11.0.","status":"published","published":"2026-08-31T22:17:22.353Z","modified":"2026-11-03T23:17:57.27Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-22","CWE-73","CWE-94"],"updated_at":"2026-11-04T01:48:35.373435Z"}],"osv":[{"id":"CVE-2026-82393","title":"pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install","description":"pnpm is a package manager. Prior to 10.34.5 and 11.11.0, pnpm accepts a scoped path traversal in a tarball dependency's package.json manifest name because pnpm11/resolving/npm-resolver/src/pickPackage.ts rejects slash characters only for unscoped names. During pnpm install, the unvalidated name reaches raw path joins in pnpm11/installing/deps-resolver/src/resolvePeers.ts, pnpm11/installing/deps-resolver/src/index.ts, and pnpm11/deps/graph-builder/src/lockfileToDepGraph.ts, causing package extraction outside node_modules and allowing attacker-controlled files to overwrite arbitrary filesystem paths even when --ignore-scripts is used. The overwrite can replace shell startup files, Git hooks, or installed package code and lead to code execution. This issue is fixed in versions 10.34.5, and 11.11.0.","status":"published","published":"2026-08-31T21:12:09.196Z","modified":"2026-11-05T02:31:05.125265821Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-22","CWE-73","CWE-94"],"updated_at":"2026-11-07T03:08:10.967759Z"},{"id":"GHSA-vq4v-j7r6-jq4m","title":"pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install","description":"## Summary\nWhen resolving a package, pnpm uses the resolved **manifest `name`** as a raw path segment for the isolated-linker import target. A tarball dependency whose `package.json` `name` is a scoped path traversal (`@x/../../…/\u003cabs path\u003e`) is therefore extracted **outside `node_modules`**, to an attacker-chosen absolute path, and can **overwrite existing files** there. Attacker controls the destination, filenames, and contents → arbitrary file write → **code execution** (e.g. `~/.zshrc`, `.git/hooks/pre-commit`, another package's code). Occurs during `pnpm install` **even with `--ignore-scripts`** (no lifecycle scripts run), defeating that safety.\n\nSame class as the just-patched **GHSA-hwx4** (transitive-dependency *alias* traversal) and **GHSA-v23m** (`stage download` manifest name/version traversal), in a sink their fixes did not cover: the isolated-linker import target keyed by the resolved **name**.\n\n## Root cause\n- The isolated-linker import target is built with a raw `path.join(modules, \u003cresolved name\u003e)` in `installing/deps-resolver/src/resolvePeers.ts:706`, `installing/deps-resolver/src/index.ts:614`, and `deps/graph-builder/src/lockfileToDepGraph.ts:233` — **without** the `safeJoinModulesDir` guard used on the symlink/hoisted/bin paths (`installing/deps-restorer/src/lockfileToHoistedDepGraph.ts:222`). The store location is `node_modules/.pnpm/\u003cid\u003e/node_modules/\u003cname\u003e`, so a traversal `\u003cname\u003e` escapes.\n- The only resolve-time name gate (`resolving/npm-resolver/src/pickPackage.ts:753`) rejects only *unscoped* names containing `/`, so a **scoped** `@x/../..` passes.\n\n## Steps to reproduce\nSelf-contained PoC (real `pnpm@11.9.0`; loopback tarball server; escape target is a throwaway temp dir):\n```\nnpm i pnpm@11.9.0\n# host a tarball whose package.json name = \"@x/\"+\"../\".repeat(25)+\"\u003cabs\u003e/OUTSIDE\"; victim depends on the http URL\npnpm install --ignore-scripts\n```\nConfirmed output (`repro/poc.mjs`, exit 0):\n```\nescape dir is outside the project        : true\nnew file implanted outside node_modules  : true\npre-existing file OVERWRITTEN            : true\n*** CONFIRMED: a tarball dependency wrote \u0026 overwrote files OUTSIDE the project during `pnpm install --ignore-scripts` ***\n```\n\n## Remediation\nRoute the isolated-linker import-target joins (`resolvePeers.ts:706`, `deps-resolver/index.ts:614`, `lockfileToDepGraph.ts:233`) through `safeJoinModulesDir` (as the hoisted linker already does), and/or enforce `validate-npm-package-name` on the resolved manifest name (close the scoped-name gap at `pickPackage.ts:753`) so the import target rejects a traversal name and re-asserts containment before any write.","status":"published","published":"2026-09-02T14:36:59Z","modified":"2026-09-02T14:45:05.975185716Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H","level":"high"}],"cwes":["CWE-22","CWE-73","CWE-94"],"updated_at":"2026-11-02T15:46:57.694388Z"}]}}
