Lack of data validation - Path Traversal In pnpm
Description
pnpm has Path Traversal via arbitrary file permission modification
Summary
When 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.
Note: Only affects Unix/Linux/macOS. Windows is not affected (fixBin gated by EXECUTABLE_SHEBANG_SUPPORTED).
Details
Vulnerable code in pkg-manager/package-bins/src/index.ts:15-21:
if (manifest.directories?.bin) { const binDir = path.join(pkgPath, manifest.directories.bin) // NO VALIDATION const files = await findFiles(binDir) // ... files outside package returned, then chmod 755'd }
The bin field IS protected with isSubdir() at line 53, but directories.bin lacks this check.
PoC
# Create malicious package mkdir /tmp/malicious-pkg echo '{"name":"malicious","version":"1.0.0","directories":{"bin":"../../../../tmp/target"}}' > /tmp/malicious-pkg/package.json # Create sensitive file mkdir -p /tmp/target echo "secret" > /tmp/target/secret.sh chmod 600 /tmp/target/secret.sh # Private...
Impact
Supply-chain attack via npm packages
File permissions changed from 600 to 755 (world-readable)
Affects non-dotfiles in predictable paths (dotfiles excluded by tinyglobby default)
Suggested Fix
Add isSubdir validation for directories.bin paths in pkg-manager/package-bins/src/index.ts, matching the existing validation in commandsFromBin():
if (manifest.directories?.bin) { const binDir = path.join(pkgPath, manifest.directories.bin) if (!isSubdir(pkgPath, binDir)) { return [] // Reject paths outside package } // ... }
Mitigation
Update Impact
Minimal update. May introduce new vulnerabilities or breaking changes.
Ecosystem | Component | Affected version | Patched versions |
|---|---|---|---|
npm | 10.28.2 |
Aliases
References