BREW-PNPM@9-CVE-2026-24131 (GHSA-V253-RJ99-JWPQ)
Vulnerability from osv_homebrew – Published: 2026-08-13 17:28 – Updated: 2026-10-08 00:56 – Source websiteSummary
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
# Install
pnpm add file:/tmp/malicious-pkg
# Check permissions
ls -la /tmp/target/secret.sh # Now 755 (world-readable)
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
}
// ...
}
{
"affected": [
{
"ecosystem_specific": {
"fix": null,
"range_state": "affected",
"upstream_fixed_in": "10.28.2"
},
"package": {
"ecosystem": "Homebrew",
"name": "pnpm@9",
"purl": "pkg:brew/pnpm%409"
},
"ranges": [
{
"events": [
{
"introduced": "9.15.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "npm",
"key": "pkg:npm/pnpm@9.15.9",
"name": "pnpm",
"strategy": "registry",
"subject_version": "9.15.9"
}
]
},
"details": "### Summary\nWhen pnpm processes a package\u0027s `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\u0027d\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 \u0027{\"name\":\"malicious\",\"version\":\"1.0.0\",\"directories\":{\"bin\":\"../../../../tmp/target\"}}\u0027 \u003e /tmp/malicious-pkg/package.json\n\n# Create sensitive file\nmkdir -p /tmp/target\necho \"secret\" \u003e /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```",
"id": "BREW-pnpm@9-CVE-2026-24131",
"modified": "2026-10-08T00:56:38Z",
"published": "2026-08-13T17:28:25Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pnpm/pnpm/security/advisories/GHSA-v253-rj99-jwpq"
},
{
"type": "WEB",
"url": "https://github.com/pnpm/pnpm/commit/17432ad5bbed5c2e77255ca6d56a1449bbcfd943"
},
{
"type": "PACKAGE",
"url": "https://github.com/pnpm/pnpm"
},
{
"type": "WEB",
"url": "https://github.com/pnpm/pnpm/releases/tag/v10.28.2"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "pnpm has Path Traversal via arbitrary file permission modification ",
"upstream": [
"GHSA-v253-rj99-jwpq",
"CVE-2026-24131"
]
}
Sightings
| Author | Source | Type | Date | Other |
|---|
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.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.