chore(monorepo): update pnpm to v11.11.0 [security] - #3
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
renovate
Bot
force-pushed
the
renovate/npm-pnpm-vulnerability
branch
from
September 6, 2026 23:33
f6d7d23 to
bccbc4e
Compare
renovate
Bot
force-pushed
the
renovate/npm-pnpm-vulnerability
branch
from
September 12, 2026 20:24
bccbc4e to
064cf48
Compare
renovate
Bot
force-pushed
the
renovate/npm-pnpm-vulnerability
branch
from
September 14, 2026 03:44
064cf48 to
0948bd8
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:
11.9.0→11.11.0>=11.9.0→>=11.11.0pnpm: 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 the GitHub Advisory Database (CC-BY 4.0).
pnpm:
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 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 the GitHub Advisory Database (CC-BY 4.0).
pnpm: Environment secrets exfiltrated via env-placeholder expansion in proxy settings read from an untrusted pnpm-workspace.yaml
GHSA-vx52-2968-3vc6
More information
Details
Summary
pnpm expands
${VAR}environment placeholders in thehttpProxy/httpsProxy/noProxysettings read from a project'spnpm-workspace.yaml. Because a project manifest is repository-controlled, a malicious repository that a victim merely clones and runspnpm installin can route all install traffic through an attacker proxy whose hostname or userinfo embeds — and thereby exfiltrates — an environment secret such asNPM_TOKENorGITHUB_TOKEN.This bypasses a trust boundary pnpm deliberately enforces: env-placeholder expansion of request-destination settings is already suppressed for
registry,pnprServer,registriesandnamedRegistrieswhen they come from an untrusted project manifest, and the sibling.npmrcreader already classifies the proxy keys as request destinations. The manifest-side guard set simply omitted them.Impact
An attacker who controls only the contents of a repository's
pnpm-workspace.yaml— a public repo, a fork, or a supply-chain pull request — can read many values out of the victim's process environment and have them delivered to an attacker-controlled host. No pre-existing access to the victim's store, global config, lockfile,node_modules, or environment is required. The secret is exfiltrated during config loading, before any lifecycle script runs.This turns "I can author a project manifest" into "I read the victim's environment secrets."
Affected versions
Introduced in pnpm 10.7.0, which added environment-variable expansion in setting names and values.
>= 11.0.0, < 11.11.0>= 10.7.0, < 10.34.5The Rust port (
pacquet) and the registry server (pnpr) are not affected.Patches
The fix adds
httpProxy,httpsProxy,noProxy,proxyandnoproxyto the request-destination key set in@pnpm/config.reader(src/getOptionsFromRootManifest.ts), so env placeholders in proxy settings from an untrusted manifest are dropped rather than expanded — matching the existingregistry/pnprServerhandling and the.npmrcreader'sisRequestDestinationValueKey. Regression tests cover the proxy keys.Workarounds
Upgrade to a patched version. Until then, do not run pnpm commands in an untrusted repository in an environment that holds secrets, or inspect the repository's
pnpm-workspace.yamlfor proxy settings before installing.Proof of concept
With
NPM_TOKENset in the victim's environment,pnpm installexpands the placeholder and routes install traffic through the attacker's host, whose hostname (and DNS query) carries the token.Unit level:
Using
registryorpnprServerin place ofhttpsProxydoes not leak on either version — those keys were already guarded, which is what made the proxy keys a hole in an existing boundary rather than an unguarded surface.Credit
Reported privately. A second finding in the original report — the
Authorizationheader being retained across a same-hosthttps->httpredirect — was assessed and is not treated as a pnpm vulnerability: npm (make-fetch-happen,minipass-fetch), Yarn (got) and reqwest all compare host rather than origin, and a registry that redirects from HTTPS to plaintext HTTP is itself the broken component. That behavior is being discussed publicly at https://github.com/orgs/pnpm/discussions/13598.Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
pnpm: A tarball dependency's manifest
nameescapes node_modules → arbitrary file write/overwrite on installCVE-2026-82393 / GHSA-vq4v-j7r6-jq4m
More information
Details
Summary
When resolving a package, pnpm uses the resolved manifest
nameas a raw path segment for the isolated-linker import target. A tarball dependency whosepackage.jsonnameis a scoped path traversal (@x/../../…/<abs path>) is therefore extracted outsidenode_modules, to an attacker-chosen absolute path, and can overwrite existing files there. Attacker controls the destination, filenames, and contents → arbitrary file write → code execution (e.g.~/.zshrc,.git/hooks/pre-commit, another package's code). Occurs duringpnpm installeven with--ignore-scripts(no lifecycle scripts run), defeating that safety.Same class as the just-patched GHSA-hwx4 (transitive-dependency alias traversal) and GHSA-v23m (
stage downloadmanifest name/version traversal), in a sink their fixes did not cover: the isolated-linker import target keyed by the resolved name.Root cause
path.join(modules, <resolved name>)ininstalling/deps-resolver/src/resolvePeers.ts:706,installing/deps-resolver/src/index.ts:614, anddeps/graph-builder/src/lockfileToDepGraph.ts:233— without thesafeJoinModulesDirguard used on the symlink/hoisted/bin paths (installing/deps-restorer/src/lockfileToHoistedDepGraph.ts:222). The store location isnode_modules/.pnpm/<id>/node_modules/<name>, so a traversal<name>escapes.resolving/npm-resolver/src/pickPackage.ts:753) rejects only unscoped names containing/, so a scoped@x/../..passes.Steps to reproduce
Self-contained PoC (real
pnpm@11.9.0; loopback tarball server; escape target is a throwaway temp dir):Confirmed output (
repro/poc.mjs, exit 0):Remediation
Route the isolated-linker import-target joins (
resolvePeers.ts:706,deps-resolver/index.ts:614,lockfileToDepGraph.ts:233) throughsafeJoinModulesDir(as the hoisted linker already does), and/or enforcevalidate-npm-package-nameon the resolved manifest name (close the scoped-name gap atpickPackage.ts:753) so the import target rejects a traversal name and re-asserts containment before any write.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 the GitHub Advisory Database (CC-BY 4.0).
pnpm: Virtual store linker path traversal via unvalidated depPath name in lockfileToDepGraph
CVE-2026-82392 / GHSA-c59q-g84q-2gj5
More information
Details
Summary
The virtual store linker constructs package installation directories using
path.join(modules, pkgName)wherepkgNameis extracted from lockfilepackageskeys viadp.parse(depPath).namewithout validation. A craftedpnpm-lock.yamlwith traversal sequences in depPath keys (e.g.,../../../tmp/pwned@1.0.0) causes package content to be written to arbitrary filesystem paths duringpnpm install.This is an incomplete fix of GHSA-fr4h-3cph-29xv — the
safeJoinModulesDircontainment helper was applied to the hoisted linker andsymlinkDependencybut NOT to the virtual store linker'slockfileToDepGraph.ts:233.Details
Root Cause
dp.parse()atpnpm11/deps/path/src/index.ts:135extracts the package name as:This is a raw substring operation with zero validation that
nameis a valid npm package name. A depPath of../../../tmp/pwned@1.0.0yieldsname = '../../../tmp/pwned'.Vulnerable Code Path
pnpm-lock.yaml→lockfile.packages['../../../../../../../tmp/pwned@1.0.0'](attacker-controlled lockfile key)nameVerFromPkgSnapshot(depPath, pkgSnapshot)atlockfile/utils/src/nameVerFromPkgSnapshot.ts:16→ callsdp.parse(depPath)→ returns{ name: '../../../../../../../tmp/pwned' }lockfileToDepGraph.ts:232→modules = path.join(dirInVirtualStore, 'node_modules')lockfileToDepGraph.ts:233→dir = path.join(modules, pkgName)→ resolves to/tmp/pwned(ESCAPES virtual store)storeController.importPackage(depNode.dir, ...)→ writes package content to the traversed pathWhy Existing Defenses Don't Catch It
depPathToFilename()— replaces/with+for thedirInVirtualStorepath, butpkgNamecomes SEPARATELY fromdp.parse()and is NOT passed through this functionverifyLockfileResolutions()— validates dependency map keys (aliases) viaisValidDependencyAlias(), but never validates the depPath keys themselvesyaml.load(lockfileRawContent)with no schema validation onpackageskeysimportPackage()— acceptstargetDirand passes it directly tocafsStore.importPackage(targetDir, ...)with zero containment checkEscalation to RCE (non-default config)
When
dangerouslyAllowAllBuilds: trueis configured (or the traversal package name is in the explicitallowBuildslist), the same traversed path is used in the rebuild phase atafter-install/src/index.ts:402,470. The attacker'spostinstallscript then executes with the victim's shell access. Under default config,allowBuildreturns false for unknown packages, limiting impact to arbitrary file write.Also Affected (PnP linker)
When
nodeLinker: pnpis configured,lockfileToPackageRegistry()atlockfile/to-pnp/src/index.ts:105-110uses the same unvalidateddp.parse().nameinpackageLocationconstruction, allowing the.pnp.cjsresolver map to point outside the virtual store. This is a lower-impact variant (PnP is not the default linker).Impact
An attacker who can commit a crafted
pnpm-lock.yamlto a repository (or supply one via a malicious package) can cause arbitrary file writes on the machine of any user who runspnpm install. Written content is the actual package files from a real npm package (attacker controls which package and which destination).Targets for arbitrary file write include:
.git/hooks/pre-commit— code execution on next git operation~/.local/bin/— binary hijackingReproduction
Craft a
pnpm-lock.yaml:Run
pnpm install— package content is written to/tmp/pwned/instead of the virtual store.Recommended Fix
Apply
safeJoinModulesDir(or equivalent validation) at:lockfileToDepGraph.ts:233—path.join(modules, pkgName)after-install/src/index.ts:402—path.join(pkgModulesDir(depPath), pkgInfo.name)lockfile/to-pnp/src/index.ts:105-110— PnPpackageLocationAlternatively, validate depPath keys during lockfile parsing to reject any that don't produce valid npm package names via
dp.parse().Relationship to GHSA-fr4h-3cph-29xv
GHSA-fr4h-3cph-29xv fixed the hoisted linker path (
lockfileToHoistedDepGraph.ts:222) by addingsafeJoinModulesDir. The same fix was NOT applied to the virtual store linker, which uses the identicaldp.parse().name → path.join()pattern atlockfileToDepGraph.ts:233.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 the GitHub Advisory Database (CC-BY 4.0).
Release Notes
pnpm/pnpm (pnpm)
v11.11.0: pnpm 11.11Compare Source
Minor Changes
508b8c2: Added thepnpm accesscommand for managing package access and visibility on the registry, supporting listing packages and collaborators, getting and setting package status and MFA requirements, and granting or revoking team access.Patch Changes
c70e33e: AllowallowBuildsentries for git-hosted packages to match by repository URL without pinning the resolved commit hash. This lets trusted git repositories keep running their build scripts after branch updates without approving each new commit, while package-name-only rules still do not approve git-hosted artifacts.3067e4f: Reduced peak memory usage during cold-cache dependency resolution. The metadata fetch is memoized for the whole resolution phase, and it was retaining each package's raw registry response body (used only to mirror the response to disk) for that entire time. The memoized cache now holds a body-less copy, so the raw body only lives as long as the call that writes the disk mirror. On large graphs that fetch full metadata (e.g. withminimumReleaseAgeortrustPolicyenabled) this cuts peak RSS by roughly 30%, back in line with pnpm 10. The resolved lockfile is unchanged.51300fd: Prevent a craftedpnpm-lock.yamlfrom writing package content outside the virtual store. A dependency path key whose name reconstructs to a path-traversal sequence (e.g.../../../tmp/x@1.0.0) is now rejected by the isolated (virtual-store) linker and the Plug'n'Play resolver map, matching the containment already applied to the hoisted linker. Under the global virtual store, a traversal in the version-derived path segment (e.g. a snapshotversion: "../../x") is now rejected atformatGlobalVirtualStorePath, the single point every global-virtual-store slot path funnels through — closing the same escape in the isolated linker, the resolver's dependency-graph builder, and the config-dependency installer.f8058eb: Reject symlinkedpnpm-lock.yamlfiles when reading or writing the env lockfile document.9318a11: AllowregistriesandnamedRegistriesto be configured in the globalconfig.yamlfile.51300fd: Fixed a path traversal vulnerability where a dependency whose manifestnamewas a scoped path traversal (e.g.@x/../../../<path>) could be written outsidenode_modulesto an attacker-controlled location duringpnpm install, even with--ignore-scripts. The isolated linker now validates the package name before using it as a directory name, matching the existing protection in the hoisted linker.14332f0: Fail instead of silently removing an optional dependency's locked entries frompnpm-lock.yamlwhen the registry cannot resolve it. Previously, when registry metadata lacked a version that the lockfile already pinned (for example, a mirror that had not synced a recent release yet),pnpm installandpnpm dedupesilently dropped the optional dependency's entries — emptying maps such as the platform binaries of@napi-rs/canvas— so the lockfile differed between machines and frozen installs on other hosts had nothing to link #12853.fecfe83: Fixed peer dependency resolution withautoInstallPeerswhen a workspace package depends on a version of a package that a transitive dependency's self-contained closure also provides for itself. The peer providers that are attached to the root project for reuse are no longer peer-resolved a second time in the root context, so packages inside such a closure no longer get their peers bound to the root project's incompatible version #4993.5a4daec:${...}environment-variable placeholders in thehttpProxy,httpsProxy,noProxy,proxy, andnoproxysettings are no longer expanded when these settings come from a project'spnpm-workspace.yaml. They now receive the same protection already applied toregistry,namedRegistries, andpnprServer.d1da02e:pnpm publishno longer prints credentials when the target registry is configured with inlineuser:pass@credentials (e.g.registry=https://user:pass@example.com/). They are now redacted both from the "publishing to registry" line and from the OIDC (trusted publishing) failure messages.dcfc611:pnpm self-updatenow honorstrustPolicy=no-downgrade. It resolves the target pnpm version against full registry metadata, so it refuses to switch to a version whose supply-chain trust evidence is weaker than an earlier-published one, the same way a regular install does.a8ad82d: Register thepnalias in generated shell completion scripts.25bd5c3: Fixed standalone installer downgrades from pnpm v12 to v11.23996e9:pnpm runtime set <name> <version>now validates its arguments: the name must benode,deno, orbun, and the version must not contain a comma. Previously these were interpolated straight into apnpm addselector, where an unsupported name or a comma (e.g.node 22,is-positive) could be misread as a list of packages or a local directory and install unintended packages or bins.Platinum Sponsors
Gold Sponsors
v11.10.0: pnpm 11.10Compare Source
Minor Changes
e2e3c81: Added theissuescommand as an alias ofbugs, sopnpm issuesopens the package's bug tracker URL in the browser.8491f8e: Added theprefixcommand which prints the current package prefix directory (or global prefix directory if-g/--globalis used).3425e80: Added an_authsetting for configuring registry authentication as a single structured (URL-keyed) value. It can be set in the global pnpm config (config.yaml) or, for CI, via thepnpm_config__authenvironment variable. The env form sidesteps the GitHub Actions / bash / zsh limitation that broke the existingpnpm_config_//host/:_authToken=…form (env var names containing/,:, or.are silently dropped). Closes #12314.The value is keyed by registry URL so each secret is explicitly bound to the host that may receive it. Registry URL keys must use
httporhttpsand must not include credentials, query strings, or fragments:The equivalent in the global
config.yaml:Within each registry URL,
@means registry-wide/default credentials and package scopes like@orgbind credentials to that scope on the same host. The only supported credential field isauthToken(maps to_authToken/ bearer auth); the deprecatedbasicAuth/username+passwordforms are intentionally not accepted here.Each entry also infers a trusted registry route:
@routes the default registry (andpnpm add <pkg>resolves there), and@orgroutes that scope. Because the credential and destination host arrive in one trusted value, repo-controlledpnpm-workspace.yamlor project.npmrccannot redirect the token to a different host._authis honored only from the env var and the global config — it is ignored in a projectpnpm-workspace.yaml/.npmrc, so repo-controlled config can never supply registry auth. Precedence: CLI flags (--registry,--@scope:registry) >pnpm_config__auth> globalconfig.yaml_auth>pnpm-workspace.yaml.Both
pnpm_config__auth(lowercase, documented form) andPNPM_CONFIG__AUTH(all-caps, the shell convention some CI runners apply) are honored. If both are set, lowercase wins unless it is empty, in which case uppercase is used. The env var wins over the globalconfig.yaml_authon a conflicting key.tokenHelperis not supported in_auth. Parsing is strict: a malformed value (bad JSON, wrong shape, invalid registry URL or scope, an unsupported credential field) fails fast with an error rather than being silently dropped.Pacquet parity note: the pacquet (Rust) port supports the same single credential field as the TS CLI:
authToken.a33eeec:pnpm self-updateandpackageManagerversion-switching can now install and link pnpm v12 (the Rust port), published with equal content under both thepnpmand@pnpm/exenames on thenext-12dist-tag. Its native binaries ship as@pnpm/exe.<platform>-<arch>packages, which pnpm's built-in installer links directly — no Node.js launcher, so the command pays no Node startup cost. v12 is initialized exactly like@pnpm/exe, including per-platform global-virtual-store hashing. From v12 onward the install converges on the unscopedpnpmpackage (the Rust exe) — even when updating from the SEA@pnpm/exebuild.1dd12bd: When resolving through a pnpr install-accelerator server, pnpm no longer forwards its own upstream registry credentials in the resolve request. Only theAuthorizationheader identifying the caller to pnpr is sent. The pnpr server now selects upstream credentials from its own route policy (operator-configured upstream credential aliases), so private dependencies resolve through a pnpr-managed alias the caller is authorized to use, rather than by sending the client's registry tokens to the server.1e81761: Expose web authenticationauthUrlanddoneUrlin JSON error output when OTP is required in a non-interactive terminal #12724.Patch Changes
2f389d6: Added the Node.js release team's new signing key (Stewart X Addison,655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD) to the embedded Node.js release keys, so runtimes whoseSHASUMS256.txtis signed by the new releaser verify successfully.acbdb94: Fixed shell tab completion not suggesting workspaces after the-Falias for--filteroption.dcabb78: Fixedpnpm up -r <pkg>bumping unrelated packages that have open semver ranges. Previously, any update mutation nullified the lockfile-derivedpreferredVersionsglobally, so packages with^x.y.zranges could re-resolve to newer compatible versions even though the user only asked to update a specific package. The install layer now always seedspreferredVersionsfrom the lockfile, and caller-supplied preferred versions (such as the vulnerability penalties ofpnpm audit --fix) layer on top of the seed instead of replacing it. The targeted package still bumps: the per-resolveupdateRequestedflag makes the resolver ignore the target's own lockfile pins.Closes #10662.
d539172: Fixed pnpm pack and pnpm publish failing when prepack generates files that are included in the package and postpack cleans them up.be6505a: Hardened global package management:node.exeflavor of a bin, so a stalenode.exeno longer survives onPATHafter uninstall, and a new global install no longer silently overwrites an existingnode.exe.pnpm add -g pnpm@<version>(and@pnpm/exe@<version>) is now rejected like the barepnpmform, pointing topnpm self-update.node_modulespaths, preventing a tampered manifest from escaping the install directory.25c7388: pnpm now rejectsjsr:specifiers whose package name is not a valid npm package name — an empty scope or name (e.g.jsr:@scope/), path separators inside the name, or any other shapevalidate-npm-package-namerejects — withERR_PNPM_INVALID_JSR_PACKAGE_NAMEinstead of silently converting them into a malformed@jsr/...npm package name.25c7388: pnpm now rejects named-registry specifiers (e.g.gh:) whose package name is not a valid npm package name — an empty scope (e.g.gh:@/bar), path separators inside the name (e.g.gh:@scope/../name), or any other shapevalidate-npm-package-namerejects — withERR_PNPM_INVALID_NAMED_REGISTRY_PACKAGE_NAMEinstead of passing the name through to registry URLs and metadata cache file paths.96da7c5: node-gyp'sgyp_main.pyandgypentrypoints are now packed with the executable bit in thepnpmand@pnpm/exetarballs. Without it, building native addons from source could fail with a permission error.99982b9: Sped up resolution and reduced memory use against registries that ignore npm's abbreviated metadata format and always return the full package document (for example, Azure DevOps Artifacts). pnpm now strips such documents down to the abbreviated field set before caching them. Resolution output is unchanged, and registries that honor the abbreviated format (such as the npm registry) pay no extra cost.11a7fdd: Sped up offline and--prefer-offlineresolution on large workspaces (e.g.pnpm dedupe --offline,pnpm install --offline). Package metadata loaded from the local cache is now kept in memory, so each package's metadata is parsed once per command instead of once per dependent that references it.2c7369d:pnpm pack-appnow rejects--entry/pnpm.app.entryand--output-dir/pnpm.app.outputDirvalues that are absolute paths or escape the project directory via..(or a symlink that resolves outside it), and refuses to write the produced executable when its target path already exists as a symlink (or other non-regular file). This prevents a repository-controlledpackage.jsonfrom embedding host files (such as an SSH key) into the produced executable, writing build artifacts outside the project, or overwriting an arbitrary file through a committed symlink. The new error codes areERR_PNPM_PACK_APP_ENTRY_OUTSIDE_PROJECT,ERR_PNPM_PACK_APP_OUTPUT_DIR_OUTSIDE_PROJECT, andERR_PNPM_PACK_APP_OUTPUT_FILE_NOT_REGULAR.When ad-hoc signing macOS targets,
pnpm pack-appnow runs the systemcodesignby absolute path and resolvesldidto a location outside the project, so a repository-controllednode_modules/.binonPATHcannot hijack the signer.ce5d5a5: Relative paths inpatchedDependenciesare now resolved against the lockfile directory when computing patch file hashes, so runningpnpm installfrom a subdirectory no longer fails withENOENTlooking for the patch file in the wrong location #12762.ebb4096:pnpm peersno longer reports a conflict for a missing peer dependency that is ignored viapnpm.peerDependencyRules.ignoreMissing.dcabb78: Fixed a prototype-pollution hazard when seeding preferred versions: a dependency named__proto__in a manifest or inpnpm-lock.yamlcould write throughObject.prototype(or crash the install) while the preferred-versions map was being built. The maps are now null-prototype objects, so crafted package names land as plain keys.f38e696: Hardenedpnpm deploy --forceso it refuses unsafe deploy targets such as workspace roots, parent directories, out-of-workspace paths, and symlinked target parents.806c3ec: pnpm no longer warns about ignored project-level auth settings whenPNPM_CONFIG_NPMRC_AUTH_FILEpoints at the project.npmrc— setting it to that file is an explicit opt-in to trusting it, so auth env variables in it are expanded ["[WARN] Ignored project-level auth setting" still warns when project level .npmrc file is trusted pnpm/pnpm#12480](https://redirect.github.com/pnpm/pnpm/issues/1Configuration
📅 Schedule: (in timezone America/New_York)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about these updates again.
This PR was generated by Mend Renovate. View the repository job log.