chore(deps): update pnpm to v11 [SECURITY]#1473
Open
bfra-me[bot] wants to merge 1 commit into
Open
Conversation
55b83de to
eea2e10
Compare
eea2e10 to
a3487a6
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:
10.34.3→11.5.3pnpm:
patch-removecould delete project-selected files outside the patches directoryGHSA-72r4-9c5j-mj57
More information
Details
Summary
The
patch-removedeletion-scope issue tracked as GHSA-72r4-9c5j-mj57 / CAND-PNPM-030 has been addressed in pnpm.A crafted patch entry could resolve outside the configured patches directory and cause
pnpm patch-removeto delete an arbitrary reachable file. This patch validates the configured directory and every resolved target before unlinking anything, then deletes the final directory entry without following it.Security boundary
..while still rejecting parent traversal, Windows drive escapes, and UNC escapes.Exploit replay
Before the patch, a workspace
patchedDependenciespath that resolved outside the project causedpnpm patch-removeto delete the external sentinel. A second replay used a nested parent symlink and a dangling outside victim:realpath()returnedENOENT, yet the victim was still removed. With this patch, both paths are rejected and the outside entries remain intact.Files changed
patching/commands/src/isSubdirectory.tsperforms component-aware containment checks.patching/commands/src/patchRemove.tsvalidates the full batch, canonicalizes parents, and unlinks final entries without following them.patching/commands/test/{isSubdirectory,patchRemove}.test.tscovers traversal, nested symlinks, dangling victims, and valid removals.Commands run
Validation
git diff --check: passed./private/tmp.Patches
10.34.4: pnpm/pnpm@352ae4811.7.0: pnpm/pnpm@612a2e6Compatibility
Missing patch files remain no-ops. Valid symlinked patch directories continue to work when their canonical target stays inside the lockfile directory, and final symlinks are removed without touching their targets.
patch-removeis not yet in pacquet's command surface, so no Rust-side parity change is required.Remaining risk
Portable Node APIs do not expose directory-fd-relative
unlinkat(). A local attacker who can replace an already validated parent directory before the unlink may still win a time-of-check/time-of-use race. The reproduced repository-controlled traversal and symlink paths do not require that concurrent capability and are blocked by this patch.Written by an agent (Codex, GPT-5).
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm: Hoisted install imports lockfile alias outside node_modules
GHSA-fr4h-3cph-29xv
More information
Details
Summary
The hoisted dependency alias issue tracked as GHSA-fr4h-3cph-29xv / CAND-PNPM-059 has been addressed in both pnpm and pacquet.
A crafted lockfile alias could be joined directly under a hoisted
node_modulesdirectory. Traversal aliases could escape that directory, while reserved aliases such as.binor.pnpmcould overwrite pnpm-owned layout. This patch validates package-name semantics and path containment before graph insertion or filesystem work.Security boundary
dep.namesink.dep.0.namebefore adding the graph node or recursing.ERR_PNPM_INVALID_DEPENDENCY_NAME.Exploit replay
Before the patch, a traversal alias in a hoisted lockfile imported package files outside the intended install root. With this patch, both pnpm and pacquet reject the alias before graph insertion or filesystem work, and the escaped file is not created.
Files changed
fs/symlink-dependency/src/safeJoinModulesDir.tsprovides the TypeScript containment helper.installing/deps-restorer/src/lockfileToHoistedDepGraph.tsvalidates the parsed dependency name at the hoisted graph sink.pacquet/crates/package-manager/src/{hoisted_dep_graph.rs,safe_join_modules_dir.rs}mirrors that boundary in Rust.Commands run
Validation
cargo fmt, parsed two-document lockfile validation, andgit diff --check: passed.Patch
Ready-for-review private PR: https://github.com/pnpm/pnpm-ghsa-fr4h-3cph-29xv/pull/1
GitHub reports the branch as mergeable and has requested review from
zkochan. GitHub intentionally does not run status checks on temporary private-fork PRs; the commands and outcomes above are the recorded local validation: https://docs.github.com/code-security/security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerabilityCompatibility
Valid unscoped and scoped package aliases continue to work. The changeset covers
@pnpm/fs.symlink-dependency,@pnpm/installing.deps-restorer, andpnpm; pacquet is updated in the same commit for CLI parity.Written by an agent (Codex, GPT-5).
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm: Path traversal in configDependencies env lockfile allows symlink creation outside node_modules/.pnpm-config
GHSA-qrv3-253h-g69c
More information
Details
Summary
pnpmaccepts package names from the env lockfileconfigDependenciessection and uses those names directly when creating config dependency symlinks undernode_modules/.pnpm-config.A malicious repository can commit a crafted
pnpm-lock.yamlwhose env-lockfile document contains a traversal-shaped config dependency name such as../../PWNED_CFGDEP. Duringpnpm install, pnpm installs the config dependency and creates a symlink at a path derived from that name.In local testing against pnpm
v11.5.1, this caused pnpm to create a symlink outside the intended config dependency directory:This works with
--ignore-scripts, so it does not rely on lifecycle script execution.Vulnerable behavior
The vulnerable behavior appears to be that
configDependencieskeys from the env lockfile are trusted as package names and used in filesystem paths without rejecting traversal components.The relevant pattern is:
If
pkgNameis attacker-controlled and contains.., thenpath.join(configModulesDir, pkgName)can resolve outsidenode_modules/.pnpm-config.Impact
A malicious project can cause pnpm to create symlinks outside the intended
node_modules/.pnpm-configdirectory during install.This gives an attacker a filesystem write primitive in the victim project directory, and potentially outside it with deeper traversal payloads, depending on path permissions and platform behavior.
The issue is especially relevant because:
pnpm-lock.yaml.pnpm install.--ignore-scripts.Local proof of concept
The following local-only PoC creates a temporary project, starts a local fake registry on
127.0.0.1, writes a malicious env-lockfile entry, runs pnpm, and checks whether pnpm created a symlink outsidenode_modules/.pnpm-config.Command used:
Observed output:
pnpm output:
The PoC then detected the escaped symlink:
Malicious lockfile structure
The malicious input is an env-lockfile
configDependencieskey containing traversal components:pnpm accepts the traversal-shaped name and reports it as installed:
Security boundary violation
The intended config dependency root was:
But pnpm created:
This demonstrates that a config dependency name from the lockfile can escape the directory where config dependencies should be linked.
Suggested remediation
Validate every
configDependencieskey loaded from the env lockfile before using it as a package name or path component.Recommended fixes:
Reject env-lockfile
configDependenciesnames that are not valid npm package names.Reject names containing absolute paths,
.components,..components, backslashes, or platform-specific path separators.Use containment-checked path joining before creating symlinks:
node_modules/.pnpm-config,Apply the same validation to config dependency subdependencies and optional dependency names read from the env lockfile.
Intersect env-lockfile
configDependencieswith the effectivepnpm-workspace.yamlconfigDependenciesbefore installing, so extra lockfile-only entries are rejected.A safe destination check should enforce behavior equivalent to:
Name validation should happen before this check, not instead of it.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:H/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
pnpm: Repository-controlled configDependencies can select a pacquet native install engine
CVE-2026-55697 / GHSA-gj8w-mvpf-x27x
More information
Details
Maintainer Action Plan
This report is ready to review with the shared patch branch. Start with the PR and the expected fixed behavior, then use the detailed exploit narrative below only if you want to replay the original path.
CAND-PNPM-097/GHSA-gj8w-mvpf-x27xsecurity/ghsa-batch-2026-06-09a93449314f398cf4bdf2e28d033c02d37395ad22origin/main55a4035abf1ae3fe7208ba1f5ef43c5eff58ccecstart-herepnpm configDependencies / pacquet delegationnpm:pnpm,npm:@​pnpm/config.reader,npm:@​pnpm/installing.commandsCWE-829,CWE-78,CWE-4947.5/CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:HExpected Patched Behavior
config-dependency pacquet install engines are not selected unless the trusted allowlist is set outside the repository; the marker file is not created.
Files And Tests To Review
config/reader/src/Config.tsconfig/reader/src/types.tsconfig/reader/src/configFileKey.tsconfig/reader/src/index.tsconfig/reader/test/index.tsinstalling/commands/src/installDeps.tsinstalling/commands/test/runPacquet.tspnpm/test/install/pacquet.ts.changeset/lucky-config-plugin-pnpmfiles.mdFocused Validation
Run these from a checkout of the shared patch branch. They are the useful maintainer commands with machine-local artifact paths removed.
The full patched replay for the shared branch passed with all 20 candidates marked fixed. This candidate's replay evidence is
results/CAND-PNPM-097-patched-result.json.Summary
pnpm can install
configDependenciesdeclared inpnpm-workspace.yamlbefore command dispatch. Before the patch, a repository could declarepacquetor@pnpm/pacquetas a config dependency and pnpm treated that repository-controlled dependency as an install-engine opt-in. During install, pnpm resolved a platform-specific@pacquet/<platform>-<arch>/pacquetbinary fromnode_modules/.pnpm-config/<packageName>and spawned it as the developer or CI user.Details
The vulnerable source-to-sink path was:
config/reader/src/getOptionsFromRootManifest.tscopies repositorypnpm-workspace.yamlconfigDependenciesinto config.pnpm/src/getConfig.tsinstalls config dependencies before command dispatch.installing/env-installer/src/resolveAndInstallConfigDeps.tsresolves the repository-declared dependency and its optional platform subdependencies.installing/env-installer/src/installConfigDeps.tsfetches, imports, and symlinks the config dependency tree undernode_modules/.pnpm-config.installing/commands/src/installDeps.tsselected pacquet delegation wheneverconfigDependenciescontainedpacquetor@pnpm/pacquet.installing/deps-installer/src/install/index.tscalledopts.runPacquetfrom frozen and materialization paths.installing/commands/src/runPacquet.tsresolved@pacquet/${process.platform}-${process.arch}/pacquetfrom the installed config dependency package and executed it withspawn().Exact-version, integrity, and platform filters only proved which bytes package resolution selected; they did not establish that the repository was trusted to choose a native install engine.
PoC
Standalone PoC and verification script:
Repository fixture:
Registry package shape:
{ "name": "pacquet", "version": "0.2.2", "optionalDependencies": { "@​pacquet/darwin-arm64": "0.2.2" } }Platform package payload:
Pre-patch exploit model:
pnpm installin the repository..pnpm-config.installDeps()treats the presence ofconfigDependencies.pacquetorconfigDependencies["@​pnpm/pacquet"]as authorization to delegate install materialization.runPacquet()resolves the platform binary from the installed config dependency tree and spawns it in the lockfile directory.Observed PoC output:
{ "primitive": "repository-selected pacquet config dependency reaches native process execution when selected", "patchedWithoutAllowlist": "blocked", "trustedAllowlist": "allows explicit opt-in" }Focused validation commands:
Validation result:
getPacquetConfigDependencyName()returnsundefinedwithout a trusted allowlist.getPacquetConfigDependencyName()allows exactpacquet, exact@pnpm/pacquet, and wildcard*trusted opt-in.configDependencyInstallEngineAllowlist, whilepnpm-workspace.yamlcannot grant this permission to itself.@pnpm/config.reader,@pnpm/installing.commands, andpnpm.installing/commands/test/runPacquet.ts: 3 passed.config/reader/test/index.ts: 2 passed, 132 skipped under the focused pattern.config/reader/test/index.tsandpnpm/test/install/pacquet.ts.git diff --check: passed.Impact
A malicious repository can cause pnpm to execute a registry-selected native binary while handling dependency-management commands. The binary runs with the victim developer or CI user's filesystem, environment, registry credentials, git/SSH credentials, and network access.
Affected products
Ecosystem: npm
Package name:
pnpm,@pnpm/config.reader,@pnpm/installing.commandsAffected versions: current main before this patch, when
configDependenciescontainspacquetor@pnpm/pacquetand install paths delegate to pacquet.Patched versions: 10.34.2, 11.5.3.
Severity
Severity: High
Vector string:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:HBase score: 8.8
Rationale: attacker input is delivered through a repository and registry package, exploitation is low complexity once the victim runs pnpm, no attacker privileges are required, and user interaction is required. Successful exploitation executes a native binary in the victim user's context, with high confidentiality, integrity, and availability impact.
Weaknesses
CWE-829: Inclusion of Functionality from Untrusted Control Sphere
CWE-78: Improper Neutralization of Special Elements used in an OS Command
CWE-494: Download of Code Without Integrity Check
Patch
The patch adds a trusted opt-in gate for config-dependency install-engine delegation:
configDependencyInstallEngineAllowlist.pnpm-workspace.yamlcannot grant this permission to itself; workspace-provided values are discarded after workspace settings are merged.installDeps()delegates to pacquet only whenpacquet,@pnpm/pacquet, or*is present in the trusted allowlist.pacquetas a config dependency, but pnpm will not spawn it as an install engine unless trusted config opts in.Changed files:
config/reader/src/Config.tsconfig/reader/src/types.tsconfig/reader/src/configFileKey.tsconfig/reader/src/index.tsconfig/reader/test/index.tsinstalling/commands/src/installDeps.tsinstalling/commands/test/runPacquet.tspnpm/test/install/pacquet.tsChangeset:
.changeset/lucky-config-plugin-pnpmfiles.mdPacquet parity:
No pacquet-side code-execution sink exists for this finding. The Rust port parses and records
configDependenciesfor workspace-state compatibility, but it does not install config dependencies or select/spawn an alternate install engine from them. The user-visible trust setting is TypeScript-side today because it gates pnpm's pacquet delegation path.CVSS Reassessment
Initial CVSS remains correct for vulnerable versions:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/ 8.8 High.Final CVSS after patch: not vulnerable after patch / 0.0. The PoC no longer reaches pacquet install-engine selection or native process execution unless the victim has set a trusted allowlist outside the repository's own workspace settings.
Remaining Risk
Users can explicitly trust pacquet install-engine delegation through the new allowlist. That is intentional behavior; the closed issue is repository self-authorization of a registry-provided native install engine.
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).
Release Notes
pnpm/pnpm (pnpm)
v11.5.3: pnpm 11.5.3Compare Source
.npmrc(action may be required)Following GHSA-3qhv-2rgh-x77r, pnpm no longer expands
${ENV_VAR}placeholders that come from a repository-controlled config file, because a malicious repository could otherwise use them to leak your environment secrets (npm tokens, CI job tokens, etc.) to an attacker-controlled registry during install. This applies to:.npmrc—registry,@scope:registry, proxy URLs, URL-scoped keys (//host/…), and credential values (_authToken,_auth,_password,username,tokenHelper,cert,key);pnpm-workspace.yaml.Environment variables are still expanded in trusted config: your user-level
~/.npmrc, the global config, CLI options, and environment config.If your authentication broke after upgrading, move the token out of the committed
.npmrc:Or keep the
${NPM_TOKEN}line but put it in your user-level~/.npmrcinstead of the repo. In GitHub Actions,actions/setup-nodewithregistry-urlalready writes a user-level.npmrc, soNODE_AUTH_TOKENkeeps working. For other CI where editing each pipeline is hard, setPNPM_CONFIG_NPMRC_AUTH_FILE=.npmrc(orNPM_CONFIG_USERCONFIG=.npmrc) in the CI environment to declare the project.npmrctrusted.See https://pnpm.io/npmrc for full migration details.
Patch Changes
Stopped expanding environment variables in repository-controlled registry/proxy request destinations and registry credential values from
.npmrc, and in workspace registry URLs frompnpm-workspace.yaml. Move dynamic registry URL and token configuration to trusted user, global, CLI, or environment config.Resolve package-manager bootstrap dependencies with trusted user or CLI registry and network config, and reject package-manager env-lockfile records that do not use registry package paths with integrity-only resolutions before auto-switch execution.
Avoid writing
packageManagerDependenciestopnpm-lock.yamlwhen package manager policy is set toonFail: ignoreorpmOnFail: ignore#12228.Avoid running dependency-status auto-install when the dependency status is unavailable without a project manifest.
Using the
$version reference syntax inoverrides(e.g."react": "$react") now prints a deprecation warning. The syntax still works, but catalogs are the recommended way to keep an overridden version in sync with the rest of the workspace. Reference a catalog entry with thecatalog:protocol instead.Fixed
pnpm config get globalconfigto return the globalconfig.yamlpath again pnpm/pnpm#11962.Fixed bare
--colorso it does not consume the following CLI flag, allowing command shorthands like--parallelto expand correctly and forms likepnpm --color with current <command>to dispatch the inner command instead of failing withMISSING_WITH_CURRENT_CMD.Fix
pnpm installignoringenableGlobalVirtualStoretoggle by including it in the workspace state settings check #12142.Security: pnpm now verifies the npm registry signature of a package-manager binary before spawning it, so a cloned repository cannot make pnpm download and execute an arbitrary native binary.
This covers two paths that select an executable from repository-controlled input:
pacquet(or@pnpm/pacquet) inconfigDependenciesopts in to pnpm's Rust install engine. pnpm now verifies that the installedpacquetshim and the host's@pacquet/<platform>-<arch>binary carry a valid npm registry signature for their exactname@version, and refuses to run pacquet (failing the command) if the signature does not verify or cannot be checked. The only graceful fallback to pnpm's own engine is when pacquet has no binary for the current platform.self-update— thepackageManager/devEngines.packageManagerfield makes pnpm download and run a specific pnpm version. pnpm now verifies the registry signature ofpnpm,@pnpm/exe, and the host platform binary before installing/spawning them, and refuses to run an engine whose signature does not match a published, signed release. The check runs only on an actual download (store cache miss), so it does not add a network round trip to every command.In both cases the signature is verified over the installed integrity, against npm's public signing keys that ship embedded in the pnpm CLI (like corepack), so bytes substituted via a tampered lockfile or a repository-controlled registry fail verification — and a registry the user did not vouch for cannot supply its own signing keys. The signed packument is fetched from the configured registry, so an npm mirror works transparently. Verification fails closed: if it cannot be completed (for example, the registry is unreachable), the command fails rather than running an unverified binary. The embedded keys are kept current by a release-time check against npm's signing-keys endpoint.
Made peer-dependent deduplication deterministic. When a peer-suffixed package variant was a subset of two or more mutually incompatible larger variants, the variant it collapsed into depended on the order importers were resolved in, which varies between machines. This could resolve the same workspace to different lockfiles on different platforms and make
pnpm dedupe --checkalternate between passing and failing.Reject invalid package names and versions from staged tarball manifests before deriving filenames for
pnpm stage download.Clarified in CLI help that the pnpm store is trusted shared state and store integrity checks are corruption detection, not a tamper boundary for untrusted store writers.
Reject reserved manifest
binnames ("",".","..", and scoped forms such as@scope/..) when resolving a package's bins. These names previously passed the bin-name guard and, when joined to the global bin directory during global remove/update/add operations, could resolve to the global bin directory itself or its parent and have it recursively deleted.Require trusted package identity before package-name
allowBuildsentries can approve lifecycle scripts for git, git-hosted tarball, direct tarball, and local directory artifacts. To approve one of those artifacts explicitly, use its peer-suffix-free lockfile depPath as theallowBuildskey. Lockfile verification now rejects lockfiles where a registry-style dependency path (name@semver) is backed by a git, directory, or git-hosted tarball resolution (ERR_PNPM_RESOLUTION_SHAPE_MISMATCH), so the dependency path is a reliable artifact identity by the time scripts can run.Security: pnpm now verifies the OpenPGP signature of a downloaded Node.js runtime's
SHASUMS256.txtbefore trusting its integrity hashes.When a repository requests a Node.js runtime (e.g. via
devEngines.runtime/useNodeVersion), the download mirror is repository-configurable throughnode-mirror:<channel>. The integrity of the downloaded binary was only checked againstSHASUMS256.txtfetched from that same mirror — a circular check that a malicious mirror could satisfy by serving a tampered binary together with a matchingSHASUMS256.txt. pnpm then executes the binary (for example to run lifecycle scripts).pnpm now fetches
SHASUMS256.txt.sigand verifies the detached OpenPGP signature against the Node.js release team's public keys, which ship embedded in the pnpm CLI. A mirror that serves a tampered binary cannot also produce a valid signature, so the download fails to verify. The embedded keys are kept current by a release-time check against the canonicalnodejs/release-keyslist.The musl variants from the hardcoded
unofficial-builds.nodejs.orgmirror are not repository-configurable and are signed by a different key, so they continue to be trusted over TLS.Platinum Sponsors
Gold Sponsors
v11.5.2: pnpm 11.5.2Compare Source
Patch Changes
Peer dependency resolution now reuses the peer contexts already recorded in the lockfile when those providers are still present in the dependency graph and still satisfy the peer ranges. This avoids unnecessary peer-context rewrites during lockfile regeneration. Current manifest choices remain authoritative: a newly added, explicitly updated, or aliased direct provider, a changed nested provider, or a locked version that no longer satisfies the range still takes precedence.
The lockfile verifier now checks that a registry entry pinning an explicit
tarballURL points at the artifact the registry's own metadata lists for thatname@version. Previously a tampered lockfile could pair a trustedname@versionwith an attacker-chosen tarball URL (and a matching integrity for those bytes), so the install fetched the attacker's bytes. A mismatch — or any entry that can't be confirmed against the registry — is rejected withERR_PNPM_TARBALL_URL_MISMATCH. Non-registry resolutions (file:, git-hosted, etc.) and registry entries without an explicit tarball URL (the URL is reconstructed from name+version+registry, so it is inherently bound) are unaffected; non-standard registry tarball URLs (npm Enterprise, GitHub Packages) still pass because they match the metadata.Fix
pnpm update --recursive --lockfile-only <pkg>@​<version>crashing withInvalid Versionwhen the catalog entry for<pkg>is a version range (e.g.^21.2.10) andcatalogModeisstrictorprefer. The catalog–version comparison now skips the equality check when either side is a range rather than passing a range tosemver.eq(), so range specifiers fall through to the existing mismatch handling instead of throwing #11570.Avoided a Node.js crash when pnpm exits after network requests on Windows.
Fixed packages being materialized into the virtual store without their root-level files (
package.json,LICENSE, README, root entrypoints) when multiplepnpm installprocesses ran against the same store/workspace concurrently. The fast import path used to destructively empty the shared target directory, so a concurrent importer could wipe files another importer had already written; if the surviving files included thepackage.jsoncompletion marker, every later install treated the broken directory as complete and never repaired it. The fast path now imports directly only when it can create the target directory exclusively, and otherwise builds the package in a private temp directory and atomically renames it into place #12197.Fix dependency build scripts not running under the global virtual store (
enableGlobalVirtualStore).In a workspace install, dependency build scripts are deferred to a single
rebuildpass (buildProjects). That pass resolved each package's location from the classicnode_modules/.pnpm/<depPathToFilename>layout, which does not exist under the global virtual store — so native dependencies (e.g. packages usingnode-gyp/prebuild-install) were never built and failed to load at runtime (Cannot find module .../build/Release/*.node).buildProjectsnow resolves the global-virtual-store projection directory (<storeDir>/links/<hash>, computed with the same graph hash the installer uses) whenenableGlobalVirtualStoreis set, and serializes concurrent builds of the same shared projection so parallel workspace projects don't race on the same directory.Don't promote a
runtime:dependency (such as the Node.js version fromdevEngines.runtimeorpnpm runtime set) into a catalog whencatalogModeisstrictorprefer. Aruntime:dependency round-trips todevEngines.runtime, which only recognizes theruntime:protocol; cataloging it rewrote the manifest entry tocatalog:, which broke that round-trip, stranded it indevDependencies, and leftdevEngines.runtimeuntouched.Skip lockfile
minimumReleaseAge/trustPolicyverification for non-registry tarball protocols (for examplefile:), so local tarball dependencies are not incorrectly checked against npm registry metadata.Platinum Sponsors
Gold Sponsors
v11.5.1: pnpm 11.5.1Compare Source
Patch Changes
pnpm auditperformance by pruning non-vulnerable lockfile subtrees and stopping path enumeration once vulnerable findings reach the path cap.npm_config_user_agentfor root lifecycle scripts during headless installs.integrityfield of a remote (non-registry) tarball dependency when its lockfile entry is rebuilt. Re-resolving such a dependency without re-fetching it (for example viapnpm update, or when another dependency changes) produced a resolution with no integrity — URL/tarball resolvers only learn the integrity after the tarball is downloaded — so the previously recorded integrity was dropped, making later installs fail withERR_PNPM_MISSING_TARBALL_INTEGRITY#12067.repositoryfield into the{ type, url }object form when creating the publish manifest, matching npm's behavior. Some registries (e.g. Gitea/Codeberg) reject a stringrepositorywith a 500 Internal Server Error duringpnpm publish#12099.@typescript-eslint/eslint-pluginpeer-depends on both@typescript-eslint/parserandtypescript, and@typescript-eslint/parserpeer-depends ontypescript), pnpm no longer reuses a hoisted instance of the shared peer that was resolved against a different version #12079.Platinum Sponsors
Gold Sponsors
✂ Note
PR body was truncated to here.
Configuration
📅 Schedule: (in timezone America/Phoenix)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate.