Security patches (dev) - #387
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
renovate
Bot
force-pushed
the
renovate/dev-security-patches
branch
from
September 2, 2026 20:46
19de0f4 to
c230174
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.06.15.2→6.16.0pnpm: 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 OSV and 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 OSV and 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 OSV and the GitHub Advisory Database (CC-BY 4.0).
qs: Denial of Service via Attacker Controlled isBuffer
CVE-2026-82417 / GHSA-4mjr-xmp4-gh2g
More information
Details
Summary
qs.stringify()callsutils.isBuffer()on every value it serializes, andutils.isBuffer()invokesobj.constructor.isBuffer(obj)without checking that it is callable. A value whose ownconstructor.isBufferis a non-function makesqscall a non-callable and throwTypeError. Such a value is produced byqs.parseitself from an untrusted query string whenplainObjects: trueorallowPrototypes: trueis set, so a pure-qsparse→stringifyround-trip — noJSON.parse— turns an unauthenticated query string into an uncaught throw.An attacker-controlled
parseinput reaches the host application's availability asset — viaqs's own recommendedplainObjectsmitigation — and triggers an uncaught exception during aparse→stringifyround-trip.Details
utils.isBufferruns atlib/stringify.js:127for every serialized value:utils.isBuffer(lib/utils.js:327-333) invokesobj.constructor.isBufferwithout verifying it is callable:constructorandisBufferare ordinary keys.qs.parsewithplainObjects: trueorallowPrototypes: truekeeps them as own properties, so the parsed value carries a non-functionconstructor.isBuffer;stringifythen calls a non-callable and throwsTypeError. By contrastutils.isRegExpuses a brand check (Object.prototype.toString); the missing guard here is an internal inconsistency, not a platform limitation.Trust Boundary Note
qs.stringifyalone treats its input as caller-constructed, so serializing a hostile object could be argued outside its contract. This report does not depend on that framing: the malicious shape is produced byqs.parse, whose input is untrusted by design.qs.parsenormally strips aconstructorkey via its prototype guard, but with the documented optionsplainObjects: trueorallowPrototypes: truethe key survives and lands as an own property. Feeding the parsed object back intoqs.stringify— the standard round-trip in gateways and request-forwarders — then hits the unchecked call.PoC
poc02c_isBuffer_qs_only_roundtrip.js— pure-qschain, noJSON.parse; an untrusted query string alone reaches the throw:poc02_isBuffer.js— the minimal defect:poc02b_isBuffer_async_crash.js— worker death in an async sink:Execution Steps
Reproduction Evidence
poc02c_isBuffer_qs_only_roundtrip.js:poc02_isBuffer.js:poc02b_isBuffer_async_crash.js:The pure-
qsround-trip shows the malicious shape originates fromqs.parseof an untrusted query string, with noJSON.parse. The synchronoustry/catchin the async case does not catch the throw; the process exits with code 1, denying service to all requests on that worker.Impact
An unauthenticated request degrades any endpoint that re-serializes deserialized client data with
qs.stringify. The primary impact is a per-request failure: the handler throws and the framework returns HTTP 500. Where the call sits in an unguarded async continuation, the throw escapes and the worker process exits, denying service to all requests it was handling, which means a higher impact that depends on the application's error handling, not onqs.Recommended Fix
Replace the duck-type with a brand check mirroring
utils.isRegExp:If duck-typing must remain, require
typeof obj.constructor.isBuffer === 'function'before invoking and wrap the call intry/catch.Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
qs array-limit bypass via bracket-key comma parsing
CVE-2026-82562 / GHSA-x5fp-wj9c-mxmx
More information
Details
Summary
qsv6.15.3allows bracket-key input to bypassarrayLimitandthrowOnLimitExceededwhencomma: true. The inputa[]=1,2,3,4succeeds witharrayLimit: 3, while the equivalent plain-key input is rejected.Affected version tested:
Details
parseArrayValue()enforces the comma limit only for flat values. Thea[]form is marked non-flat, so its comma-separated value is wrapped after parsing and the inner array is not checked. A single parameter can therefore materialize arbitrarily large arrays.PoC
On
v6.15.3, the first input parses successfully and the second creates an array with 1,000,001 elements. The equivalenta=1,2,3,4input throwsRangeErroras expected.Impact
An attacker who can supply a query string or form body can bypass configured array limits and force excessive memory allocation, causing denial of service. The limit must be applied after comma splitting and before the resulting array is wrapped.
Severity
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
pnpm/pnpm (pnpm)
v11.11.0Compare 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.v11.10.0Compare 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 pnpm/pnpm#12480.991405e: Restore differential rendering (ansi-diff) to fix duplicated output lines introduced by #12351.c121235: Fixed the topological order of--filtered commands (pnpm run,pnpm exec,pnpm publish,pnpm pack,pnpm rebuild) when the selected projects depend on each other only transitively through projects that were not selected. Previously such selected projects could run concurrently or in the wrong order; now a project always runs after the selected projects it transitively depends on, while projects without a real dependency relationship still run concurrently. This now also holds for prod-only filters (--filter-prod), which resolve order through the production dependency graph so transitive production dependencies are respected without pulling back the dev dependencies the filter drops, and for selections that mix--filterwith--filter-prod#8335.d539172:pnpm packandpnpm publishno longer follow a symlinked workspaceLICENSEfile when injecting it into a package that has no license of its own. Following the symlink could pack bytes from outside the workspace into the published tarball.dcabb78: Fixedpnpm up <pkg>producing a different result than a fresh install of the same manifests would. The resolver now distinguishesupdateRequested(true only for packages that match the user's update target) from the broaderupdateflag, and for the targeted package ignores only its own lockfile-derived preferred-version pins — so the target re-resolves exactly as if its lockfile entries were deleted andpnpm installran. Preferred versions a fresh install applies (manifest pins, versions propagated down the dependency chain, and the vulnerability-avoidance penalties ofpnpm audit --fix) stay in effect, so an update never installs duplicate versions that a reinstall from scratch would not reproduce. When a preferred version holds the update target below the newest version its range admits, pnpm now prints a warning explaining that reaching the newer version everywhere requires an override.dcabb78:pnpm update <dep>@<version>now prints a warning when<dep>is only present as a transitive dependency: the requested version cannot be applied there (updates resolve the target the way a fresh install would), and the warning recommends adding the version topnpm.overridesinstead, which is the mechanism that does pin transitive dependencies. Closes #12744.a6c4d5f: When a dependency cannot be found in the registry (404) or the registry has no matching version, and a workspace project with the same name exists only at non-matching versions, the error now reports the available workspace versions (ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE) instead of the raw registry failure pnpm/pnpm#1379. Other registry failures (authorization, network, server errors) still propagate unchanged. The pacquet (Rust) resolver applies the same behavior.ljharb/qs (qs)
v6.16.0Compare Source
stringify: add adepthoption to bound recursion depth (defaultInfinity)parse: enforcearrayLimiton comma groups under[]=whenthrowOnLimitExceededis setparse: flatten a collection appended to an overflowed array (#571)utils:isBuffer: do not invoke a non-callableconstructor.isBufferstringify: do not letallowEmptyArraysskip cycle detection (or drop own keys) on an empty array with own propertiesstringify: encode dots in a top-level key with a primitive value when encodeDotInKeys is set (#562)stringifydeep-nesting DoS is caller-boundedarrayLimitis a representation threshold, not an element-count capparse: remove a test that pinned[]=comma groups escapingarrayLimitstringify: pin currentencodeDotInKeysseparator-dot behavior@ljharb/eslint-config,eslinteslint,evalmdv6.15.3Compare Source
parse: enforcethrowOnLimitExceededfor cumulative array growth viacombine/mergeutils: respect encoding of surrogate pairs across chunks (#559)parse: throw thearrayLimiterror before splitting oversized comma valuesutils.merge/utils.assign: avoid invoking__proto__setter when copying own propertiesutils: enforcearrayLimitconsistently acrossmerge's array pathsutils: makecompactO(n) via a side-channel visited-set instead ofArray.indexOfside-channeleslint,mock-property,tapeparse: characterize current lenient handling of unbalanced bracket keys (#558)Configuration
📅 Schedule: (in timezone Europe/Warsaw)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
👻 Immortal: This PR will be recreated if closed unmerged. Get config help if that's undesired.
This PR was generated by Mend Renovate. View the repository job log.