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.json
package/package.json
z/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.
Release Notes
pnpm/pnpm (pnpm)
### [`v7.33.4`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.4)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.33.3...v7.33.4)
##### Patch Changes
- When the same file is appended multiple times into a tarball, the last occurrence is selected when unpacking the tarball.
- Added support for `publishConfig.registry` in `package.json` for publishing [#6775](https://togithub.com/pnpm/pnpm/issues/6775).
- Fixed a bug in which pnpm passed the wrong scheme to `git ls-remote`, causing a fallback to `git+ssh` and resulting in a 'host key verification failed' issue [#6805](https://togithub.com/pnpm/pnpm/issues/6805)
##### Our Gold Sponsors
##### Our Silver Sponsors
### [`v7.33.3`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.3)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.33.2...v7.33.3)
#### Patch Changes
- Improve the performance of searching for auth tokens.
- Installation of a git-hosted dependency without `package.json` should not fail, when the dependency is read from cache [#6721](https://togithub.com/pnpm/pnpm/issues/6721).
- Local workspace bin files that should be compiled first are linked to dependent projects after compilation [#1801](https://togithub.com/pnpm/pnpm/issues/1801).
- Prefer versions found in parent package dependencies only [#6737](https://togithub.com/pnpm/pnpm/issues/6737).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.33.2`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.2)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.33.1...v7.33.2)
##### Patch Changes
- In cases where both aliased and non-aliased dependencies exist to the same package, non-aliased dependencies will be used for resolving peer dependencies, addressing issue [#6588](https://togithub.com/pnpm/pnpm/issues/6588).
- Don't crash when the APPDATA env variable is not set on Windows [#6659](https://togithub.com/pnpm/pnpm/issues/6659).
- Don't fail when a package is archived in a tarball with malformed tar headers [#5362](https://togithub.com/pnpm/pnpm/issues/5362).
- Peer dependencies of subdependencies should be installed, when `node-linker` is set to `hoisted` [#6680](https://togithub.com/pnpm/pnpm/pull/6680).
- Ignore the port in the URL, while searching for authentication token in the `.npmrc` file [#6354](https://togithub.com/pnpm/pnpm/issues/6354).
- Throw a meaningful error when applying a patch to a dependency fails.
- `pnpm update --global --latest` should work [#3779](https://togithub.com/pnpm/pnpm/issues/3779).
##### Our Gold Sponsors
##### Our Silver Sponsors
### [`v7.33.1`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.1)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.33.0...v7.33.1)
#### Patch Changes
- When `dedupe-peer-dependents` is enabled, use the path (not id) to determine compatibility.
When multiple dependency groups can be deduplicated, the latter ones are sorted according to number of peers to allow them to benefit from deduplication.
Resolves: [#6605](https://togithub.com/pnpm/pnpm/issues/6605)
- Change lockfile version back to 6.0 as previous versions of pnpm fail to parse the version correctly.
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.33.0`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.0)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.5...v7.33.0)
#### Minor Changes
- Some settings influence the structure of the lockfile, so we cannot reuse the lockfile if those settings change. As a result, we need to store such settings in the lockfile. This way we will know with which settings the lockfile has been created.
A new field will now be present in the lockfile: `settings`. It will store the values of two settings: `autoInstallPeers` and `excludeLinksFromLockfile`. If someone tries to perform a `frozen-lockfile` installation and their active settings don't match the ones in the lockfile, then an error message will be thrown.
The lockfile format version is bumped from v6.0 to v6.1.
Related PR: [#6557](https://togithub.com/pnpm/pnpm/pull/6557)
Related issue: [#6312](https://togithub.com/pnpm/pnpm/issues/6312)
#### Patch Changes
- When updating dependencies, preserve the range prefix in aliased dependencies. So `npm:foo@1.0.0` becomes `npm:foo@1.1.0`.
- Print a meaningful error when a project referenced by the `workspace:` protocol is not found in the workspace [#4477](https://togithub.com/pnpm/pnpm/issues/4477).
- Should respect ignore patterns in `updateConfig.ignoreDependencies` [#6548](https://togithub.com/pnpm/pnpm/issues/6548)
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.5`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.5)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.4...v7.32.5)
#### Patch Changes
- `pnpm rebuild` should not fail when `node-linker` is set to `hoisted` and there are skipped optional dependencies [#6553](https://togithub.com/pnpm/pnpm/pull/6553).
- Expanded missing command error, including 'did you mean' [#6492](https://togithub.com/pnpm/pnpm/issues/6492).
- Normalize current working directory on Windows [#6524](https://togithub.com/pnpm/pnpm/issues/6524).
- Build projects in a workspace in correct order [#6568](https://togithub.com/pnpm/pnpm/pull/6568).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.4`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.4)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.3...v7.32.4)
#### Patch Changes
- `pnpm link -g ` should not modify the `package.json` file [#4341](https://togithub.com/pnpm/pnpm/issues/4341).
- Node.js range specified through the `engines` field should match prerelease versions [#6509](https://togithub.com/pnpm/pnpm/pull/6509).
- `pnpm publish --otp` should work [#6514](https://togithub.com/pnpm/pnpm/issues/6514).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.3`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.3)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.2...v7.32.3)
#### Patch Changes
- Link the bin files of local workspace dependencies, when `node-linker` is set to `hoisted` [6486](https://togithub.com/pnpm/pnpm/issues/6486).
- Show cyclic workspace dependency details [#5059](https://togithub.com/pnpm/pnpm/issues/5059).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.2`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.2)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.1...v7.32.2)
#### Patch Changes
- Patch node-fetch to fix an error that happens on Node.js 20 [#6424](https://togithub.com/pnpm/pnpm/issues/6424).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.1`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.1)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.32.0...v7.32.1)
#### Patch Changes
- Warn user when `publishConfig.directory` of an injected workspace dependency does not exist [#6396](https://togithub.com/pnpm/pnpm/pull/6396).
- Use hard links to link the node executable on Windows machines [#4315](https://togithub.com/pnpm/pnpm/issues/4315).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.32.0`](https://togithub.com/pnpm/pnpm/releases/tag/v7.32.0)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.31.0...v7.32.0)
#### Minor Changes
- Allow env variables to be specified with default values in `.npmrc`. This is a convention used by Yarn too.
Using `${NAME-fallback}` will return `fallback` if `NAME` isn't set. `${NAME:-fallback}` will return `fallback` if `NAME` isn't set, or is an empty string [#6018](https://togithub.com/pnpm/pnpm/issues/6018).
#### Patch Changes
- `pnpm config get ` returns empty when the value is a boolean
- Don't print an info message about linked dependencies if they are real linked dependencies specified via the `link:` protocol in `package.json`.
- Add -g to mismatch registries error info when original command has -g option [#6224](https://togithub.com/pnpm/pnpm/issues/6224).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.31.0`](https://togithub.com/pnpm/pnpm/releases/tag/v7.31.0)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.5...v7.31.0)
#### Minor Changes
- Add `ignore-workspace-cycles` to silence workspace cycle warning [#6308](https://togithub.com/pnpm/pnpm/pull/6308).
##### Patch Changes
- Registries are now passed to the preResolution hook.
- Repeat installation should work on a project that has a dependency with () chars in the scope name [#6348](https://togithub.com/pnpm/pnpm/issues/6348).
- Should report error summary as expected.
- Update `@yarnpkg/shell` to fix issues in the shell emulator [#6320](https://togithub.com/pnpm/pnpm/issues/6320).
- Installation should not fail when there is a local dependency that starts in a directory that starts with the `@` char [#6332](https://togithub.com/pnpm/pnpm/issues/6332).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.30.5`](https://togithub.com/pnpm/pnpm/releases/tag/v7.30.5)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.4...v7.30.5)
#### Patch Changes
- `pnpm audit` should work even if there are no `package.json` file, just a `pnpm-lock.yaml` file.
- Dedupe direct dependencies after hoisting.
- Don't remove automatically installed peer dependencies from the root workspace project, when `dedupe-peer-dependents` is `true` [#6154](https://togithub.com/pnpm/pnpm/issues/6154).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.30.4`](https://togithub.com/pnpm/pnpm/compare/v7.30.3...v7.30.4)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.3...v7.30.4)
### [`v7.30.3`](https://togithub.com/pnpm/pnpm/releases/tag/v7.30.3)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.2...v7.30.3)
#### Patch Changes
- Should use most specific override rule when multiple rules match the same target [#6210](https://togithub.com/pnpm/pnpm/issues/6210).
- Fix regression introduced in v7.30.1 [#6271](https://togithub.com/pnpm/pnpm/issues/6271).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.30.2`](https://togithub.com/pnpm/pnpm/compare/v7.30.1...v7.30.2)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.1...v7.30.2)
### [`v7.30.1`](https://togithub.com/pnpm/pnpm/releases/tag/v7.30.1)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.30.0...v7.30.1)
#### Patch Changes
- Don't write the `pnpm-lock.yaml` file if it has no changes and `pnpm install --frozen-lockfile` was executed [#6158](https://togithub.com/pnpm/pnpm/issues/6158).
- Fix git-hosted dependencies referenced via `git+ssh` that use semver selectors [#6239](https://togithub.com/pnpm/pnpm/pull/6239).
- When publish some package throws an error, the exit code should be non-zero [#5528](https://togithub.com/pnpm/pnpm/issues/5528).
- Only three paths are displayed in `pnpm audit` output [#6203](https://togithub.com/pnpm/pnpm/issues/6203)
- Aliased packages should be used to resolve peer dependencies too [#4301](https://togithub.com/pnpm/pnpm/issues/4301).
#### Our Gold Sponsors
#### Our Silver Sponsors
### [`v7.30.0`](https://togithub.com/pnpm/pnpm/releases/tag/v7.30.0)
[Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.29.3...v7.30.0)
#### Minor Changes
- Allow to set a custom directory for storing patch files via the `patches-dir` setting [#6215](https://togithub.com/pnpm/pnpm/pull/6215)
#### Patch Changes
- New directories should be prepended to NODE_PATH in command shims, not appended.
- Retry copying file on EBUSY error [#6201](https://togithub.com/pnpm/pnpm/issues/6201).
#### Our Gold Sponsors
This PR contains the following updates:
7.16.1
->7.33.4
GitHub Vulnerability Alerts
CVE-2023-37478
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.json
package/package.json
z/package.json
File contents:
a/package.json
package/package.json
z/package.json
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 hasreact@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.
Release Notes
pnpm/pnpm (pnpm)
### [`v7.33.4`](https://togithub.com/pnpm/pnpm/releases/tag/v7.33.4) [Compare Source](https://togithub.com/pnpm/pnpm/compare/v7.33.3...v7.33.4) ##### Patch Changes - When the same file is appended multiple times into a tarball, the last occurrence is selected when unpacking the tarball. - Added support for `publishConfig.registry` in `package.json` for publishing [#6775](https://togithub.com/pnpm/pnpm/issues/6775). - Fixed a bug in which pnpm passed the wrong scheme to `git ls-remote`, causing a fallback to `git+ssh` and resulting in a 'host key verification failed' issue [#6805](https://togithub.com/pnpm/pnpm/issues/6805) ##### Our Gold Sponsors