GHSA-5r98-f33j-g8h7 CVE-2023-37478
pnpm incorrectly parses tar archives relative to specification
- Severity
- 7.5 / 10
- Critical · CVSS 3.1
- Exploit chance (EPSS)
- 1.20%
- Chance of exploitation in the next 30 days. Higher than 68.19% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-284 Improper Access Control
- Fix
- Available
- 9 packages have a fixed version
Description
Summary
It is possible to construct a tarball that, when installed via npm or parsed by the registry is safe, but when installed via pnpm is malicious, due to how pnpm parses tar archives.
Details
The TAR format is an append-only archive format, and as such, the specification for how to update a file is to add a new record to the end with the updated version of the file. This means that it is completely valid for an archive to contain multiple copies of, say, package.json, and the expected behavior when extracting is that all versions other than the last get ignored.
This is further complicated by that during tarball extraction, all package managers are configured to drop the first path component, so collisions can be created simply by using multiple root folders in the archive, even without performing updates.
When pnpm extracts a tar archive via tar-stream, it appears to extract only the first file of a given name and discards all subsequent files with the same name.
PoC
Create a root folder with the following layout:
a/package.jsonpackage/package.jsonz/package.json
File contents:
a/package.json
{
"name": "test-package",
"version": "0.1.0",
"description": "This is a bad version of a test package",
"dependencies": {
"react": "^15"
}
}
package/package.json
{
"name": "test-package",
"version": "0.1.0",
"description": "This is a bad version of a test package",
"dependencies": {
"react": "^16"
}
}
z/package.json
{
"name": "test-package",
"version": "0.1.0",
"description": "This is the good version of a test package",
"dependencies": {
"react": "^17"
}
}
Then use the tar binary to produce a tarball (working directory is the root folder):
tar -c -z --format ustar -f package.tgz a package z
The order of the folders at the end matters; whichever one is last will end up being the package.json that wins when extracted by npm; the one that is first will be the one that wins when extracted by pnpm.
Install the tarball via the file: protocol.
Observe that with npm, the lockfile has react@17, while with pnpm it has react@15.
Impact
This can result in a package that appears safe on the npm registry or when installed via npm being replaced with a compromised or malicious version when installed via pnpm.
Affected versions
npm
| Package | Vulnerable | Fixed in |
|---|---|---|
| @pnpm/cafs | < 7.0.5 |
7.0.5 |
| @pnpm/exe | < 7.33.4 |
7.33.4 |
| @pnpm/exe | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/linux-arm64 | < 7.33.4 |
7.33.4 |
| @pnpm/linux-arm64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/linux-x64 | < 7.33.4 |
7.33.4 |
| @pnpm/linux-x64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/linuxstatic-arm64 | < 7.33.4 |
7.33.4 |
| @pnpm/linuxstatic-arm64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/macos-arm64 | < 7.33.4 |
7.33.4 |
| @pnpm/macos-arm64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/macos-x64 | < 7.33.4 |
7.33.4 |
| @pnpm/macos-x64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| @pnpm/win-x64 | < 7.33.4 |
7.33.4 |
| @pnpm/win-x64 | >= 8.0.0, < 8.6.8 |
8.6.8 |
| pnpm | < 7.33.4 |
7.33.4 |
| pnpm | >= 8.0.0, < 8.6.8 |
8.6.8 |
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/cafs npm → 7.0.5
- npm
npm install @pnpm/cafs@7.0.5- yarn
yarn add @pnpm/cafs@7.0.5- pnpm
pnpm add @pnpm/cafs@7.0.5
@pnpm/exe npm → 7.33.4
- npm
npm install @pnpm/exe@7.33.4- yarn
yarn add @pnpm/exe@7.33.4- pnpm
pnpm add @pnpm/exe@7.33.4
@pnpm/linux-arm64 npm → 7.33.4
- npm
npm install @pnpm/linux-arm64@7.33.4- yarn
yarn add @pnpm/linux-arm64@7.33.4- pnpm
pnpm add @pnpm/linux-arm64@7.33.4
@pnpm/linux-x64 npm → 7.33.4
- npm
npm install @pnpm/linux-x64@7.33.4- yarn
yarn add @pnpm/linux-x64@7.33.4- pnpm
pnpm add @pnpm/linux-x64@7.33.4
@pnpm/linuxstatic-arm64 npm → 7.33.4
- npm
npm install @pnpm/linuxstatic-arm64@7.33.4- yarn
yarn add @pnpm/linuxstatic-arm64@7.33.4- pnpm
pnpm add @pnpm/linuxstatic-arm64@7.33.4
@pnpm/macos-arm64 npm → 7.33.4
- npm
npm install @pnpm/macos-arm64@7.33.4- yarn
yarn add @pnpm/macos-arm64@7.33.4- pnpm
pnpm add @pnpm/macos-arm64@7.33.4
@pnpm/macos-x64 npm → 7.33.4
- npm
npm install @pnpm/macos-x64@7.33.4- yarn
yarn add @pnpm/macos-x64@7.33.4- pnpm
pnpm add @pnpm/macos-x64@7.33.4
@pnpm/win-x64 npm → 7.33.4
- npm
npm install @pnpm/win-x64@7.33.4- yarn
yarn add @pnpm/win-x64@7.33.4- pnpm
pnpm add @pnpm/win-x64@7.33.4
pnpm npm → 7.33.4
- npm
npm install pnpm@7.33.4- yarn
yarn add pnpm@7.33.4- pnpm
pnpm add pnpm@7.33.4
Severity breakdown
CVSS 3.1 7.5
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H
- Attack vector
- Network
- Attack complexity
- High
- Privileges required
- Low
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Weakness
CWE-284: Improper Access Control
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
How to prevent it
- Architecture and Design, Operation: Very carefully manage the setting, management, and handling of privileges. Explicitly manage trust zones in the software.
- Architecture and Design: Compartmentalize the system to have "safe" areas where trust boundaries can be unambiguously drawn. Do not allow sensitive data to go outside of the trust boundary and always be careful when interfacing with a compartment outside of the safe area. Ensure that appropriate compartmentalization is built into the system design, and the compartmentalization allows for and reinforces privilege separation functionality. Architects and designers should rely on the principle of least privilege to decide the appropriate time to use privileges and the time to drop privileges.
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