Change8

v11.5.3

Breaking Changes
📦 pnpmView on GitHub →
3 breaking2 features🐛 10 fixes1 deprecations🔧 5 symbols

Summary

This patch release introduces significant security enhancements by verifying signatures for package manager binaries and downloaded Node.js runtimes, alongside fixes for configuration expansion, lockfile generation, and CLI flag parsing.

⚠️ Breaking Changes

  • Environment variables are no longer expanded in repository-controlled registry/proxy request destinations, registry credential values from .npmrc, and workspace registry URLs from pnpm-workspace.yaml. Users must move dynamic registry URL and token configuration to trusted user, global, CLI, or environment config.
  • 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). This enforces that dependency paths reliably reflect artifact identity before lifecycle scripts run.
  • Reserved manifest bin names ("", ".", "..", and scoped forms like @scope/..) are now rejected when resolving package bins. Previously, these could lead to recursive deletion of the global bin directory or its parent during global operations.

Migration Steps

  1. If using dynamic registry URLs or tokens configured in .npmrc or pnpm-workspace.yaml, move this configuration to trusted user, global, CLI, or environment configuration.
  2. If using "$" syntax in overrides (e.g., "react": "$react"), update to use the catalog protocol instead (e.g., "react": "catalog:react").
  3. If relying on repository-controlled inputs to select package manager engines or Node.js runtimes, ensure that the lockfile/manifest integrity matches the expected signature, or the command will fail if verification cannot be completed.

✨ New Features

  • Security: pnpm now verifies the npm registry signature of package-manager binaries (pacquet and pnpm itself) before spawning them, preventing execution of arbitrary native binaries from tampered repositories or lockfiles.
  • Security: pnpm now verifies the OpenPGP signature of a downloaded Node.js runtime's SHASUMS256.txt against embedded public keys before trusting its integrity hashes, preventing execution of tampered runtimes.

🐛 Bug Fixes

  • Fixed environment variable expansion in repository-controlled registry/proxy request destinations and registry credential values from .npmrc, and in workspace registry URLs from pnpm-workspace.yaml.
  • Resolved package-manager bootstrap dependencies to use 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.
  • Avoided writing packageManagerDependencies to pnpm-lock.yaml when package manager policy is set to onFail: ignore or pmOnFail: ignore.
  • Avoided running dependency-status auto-install when the dependency status is unavailable without a project manifest.
  • Fixed pnpm config get globalconfig to return the global config.yaml path again.
  • Fixed bare --color flag so it does not consume the following CLI flag, allowing command shorthands like --parallel to expand correctly and forms like pnpm --color with current <command> to dispatch the inner command.
  • Fixed pnpm install ignoring enableGlobalVirtualStore toggle by including it in the workspace state settings check.
  • Made peer-dependent deduplication deterministic, resolving issues where lockfile resolution depended on importer resolution order.
  • Rejected 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.

Affected Symbols

⚡ Deprecations

  • Using the "$" version reference syntax in overrides (e.g., "react": "$react") now prints a deprecation warning. Users should reference a catalog entry with the "catalog:" protocol instead.