Skip to content

fix(security): port the latest security fixes to v10#12300

Merged
zkochan merged 8 commits into
release/10from
backport/v10-security-fixes
Jun 10, 2026
Merged

fix(security): port the latest security fixes to v10#12300
zkochan merged 8 commits into
release/10from
backport/v10-security-fixes

Conversation

@zkochan

@zkochan zkochan commented Jun 9, 2026

Copy link
Copy Markdown
Member

Ports the following security fixes from main to release/10:

main commit PR v10 port
230df57 #12289 fix(package-bins): reject reserved manifest bin names
1017c36 #12291 fix: block untrusted request destination env expansion
5f2bb9f #12292 fix(security): verify npm registry signature before spawning a package-manager binary
822beb5 #12296 fix: harden package-manager bootstrap metadata
3d50680 #12295 fix(security): verify Node.js runtime SHASUMS OpenPGP signature

The v10 codebase diverges substantially from main, so these are ports, not cherry-picks. Notable adaptations:

Reject reserved manifest bin names (#12289)

  • bins/resolver does not exist on v10; the same guard lands in pkg-manager/package-bins (the code is otherwise identical).
  • The global/commands e2e test from main has no v10 home; the resolver-level test covers the guard.

Block untrusted request destination env expansion (#12291, CAND-PNPM-122 / GHSA-3qhv-2rgh-x77r)

  • v10 loads .npmrc through @pnpm/npm-conf, which expands ${...} during parsing, so the trust boundary is enforced by post-processing the project and workspace npm-conf source layers: the raw file is re-read without expansion and any setting whose raw form uses a placeholder in a request destination (registry/proxy URLs, URL-scoped keys) or in a credential value is dropped from that layer with a warning (dropUntrustedEnvExpansions.ts).
  • The pnpm-workspace.yaml side only needs the registry key on v10 (registries/namedRegistries/pnprServer are v11 features), and v10 has no trusted-yaml caller, so no expandRequestDestinationEnv flag is threaded — expansion of registry values is simply blocked.

Verify npm registry signature before spawning a package-manager binary (#12292, CAND-PNPM-097)

  • v10 has no @pnpm/deps.security.signatures package and no env-lockfile machinery; the verification lives in @pnpm/tools.plugin-commands-self-updater, which is the single chokepoint for both the automatic packageManager version switch and pnpm self-update.
  • The staged pnpm add install is verified before it is linked into the tools directory: pnpm/@pnpm/exe plus every platform binary materialized on disk must carry a valid npm registry signature over the integrity recorded in the staged lockfile, validated against npm's signing keys embedded in the CLI (corepack-style). Fails closed, including on an unreachable registry; runs only on a tools-directory cache miss.
  • The pacquet install-engine sink from main does not exist on v10.
  • The embedded keys are kept fresh by tools/plugin-commands-self-updater/scripts/update-npm-signing-keys.mjs (pnpm run check:npm-signing-keys); v10 has no create-release-pr workflow, so the check gates release.yml instead.

Harden package-manager bootstrap metadata (#12296)

  • getConfig() now computes packageManagerRegistries / packageManagerNetworkConfig from trusted config layers only (CLI, env, user and global .npmrc — never the repository's project/workspace .npmrc or pnpm-workspace.yaml), defaulting to the public npm registry. switchCliVersion() applies them to the version-switch install + verification.
  • The env-lockfile validation parts of the main PR (packageManagerLockfile.ts, syncEnvLockfile, peer-suffix handling) do not apply: v10 bootstraps through a staged child install, which already runs outside the repository's config context.

Verify Node.js runtime SHASUMS OpenPGP signature (#12295)

  • Same fix as main in @pnpm/crypto.shasums-file (fetchVerifiedNodeShasums, embedded nodeReleaseKeys.ts, update script, release gate — pnpm run check:node-release-keys).
  • The consumer on v10 is @pnpm/node.fetcher (main's engine/runtime/node-resolver doesn't exist here): releaseChannel is threaded from @pnpm/plugin-commands-env and verification is gated on the release channel, matching main (pre-release channels are unsigned by Node).
  • Bun/Deno resolvers keep using unverified SHASUMS from hardcoded GitHub URLs, matching main's scope.
  • The pacquet Rust port and Cargo changes from main do not apply to this branch.

Testing

  • New unit tests in pkg-manager/package-bins, config/config (npmrc + workspace-yaml trust boundaries, bootstrap registries), tools/plugin-commands-self-updater (9 signature-verification tests), and crypto/shasums-file (4 OpenPGP tests, ported from main).
  • Both embedded key sets verified live against their canonical sources (check:npm-signing-keys, check:node-release-keys both pass).
  • Full workspace compile + lint (spellcheck, meta-updater, eslint) pass; tests for every touched package pass locally.

Written by an agent (Claude Code, claude-fable-5).

zkochan added 5 commits June 10, 2026 00:43
Manifest bin keys "", ".", "..", and scoped forms such as "@scope/.."
passed the bin-name guard because encodeURIComponent leaves them
unchanged. When joined to the global bin directory during global
remove/update/add operations, "." resolves to the bin directory itself
and ".." to its parent, which removeBin then recursively deletes.

Reject empty, ".", and ".." bin names after scope stripping.

Backport of #12289 to v10.
Makes environment expansion trust-aware for registry/auth config and
request destinations:

- Stops project and workspace .npmrc files from expanding ${...}
  placeholders in registry/proxy request destinations, URL-scoped keys,
  and registry credential values.
- Stops repository-controlled pnpm-workspace.yaml from expanding
  ${...} placeholders in the registry setting.
- Preserves env expansion for trusted user/global/CLI/env config so
  existing token and registry setup flows continue to work.

Backport of #12291 (CAND-PNPM-122 / GHSA-3qhv-2rgh-x77r) to v10.
…e-manager binary

The packageManager field (and pnpm self-update) makes pnpm download and
run a specific pnpm version. The staged install's bytes were trusted
based on lockfile integrity alone, which proves nothing when the inputs
are repository-controlled.

pnpm now verifies the npm registry signature of the engine it is about
to spawn, over the installed integrity, against npm's public signing
keys embedded in the pnpm CLI (exactly as corepack does):

- verifyPnpmEngineIdentity() checks pnpm/@pnpm/exe and the materialized
  platform binaries of the staged install before it is linked into the
  tools directory.
- Fails closed: any verification failure, including an unreachable
  registry, refuses the version switch rather than running an unverified
  binary. Runs only on a tools-directory cache miss (an actual
  download).
- The embedded keys live in a generated file kept in sync with npm's
  keys endpoint by scripts/update-npm-signing-keys.mjs; the release
  workflow runs the check as a gate so a key rotation cannot silently
  break verification.

Backport of #12292 (CAND-PNPM-097) to v10.
Resolve package-manager bootstrap traffic through trusted user/CLI
registries and trusted network config, defaulting to the public npm
registry instead of project/workspace registry settings:

- getConfig() now computes packageManagerRegistries and
  packageManagerNetworkConfig from trusted config sources only (CLI
  options, env config, user and global .npmrc) — never the repository's
  project/workspace .npmrc or pnpm-workspace.yaml.
- switchCliVersion() applies that bootstrap config when installing and
  verifying the wanted pnpm version, so repository .npmrc
  proxy/TLS/registry values cannot steer package-manager bootstrap
  traffic.

Backport of #12296 to v10. The v11 env-lockfile validation
parts do not apply: v10 bootstraps the wanted version through a staged
child install instead of an env lockfile.
When a repository requests a Node.js runtime (useNodeVersion or an
execution env), pnpm downloads and then executes a Node binary. The
download mirror is repository-configurable via node-mirror:<channel> in
project .npmrc, and the integrity came from SHASUMS256.txt fetched from
that same mirror — a circular check a malicious mirror can satisfy with
a tampered binary and matching hashes.

pnpm now fetches SHASUMS256.txt.sig and verifies its detached OpenPGP
signature against the Node.js release team's public keys, embedded in
the pnpm CLI, before trusting the hashes:

- @pnpm/crypto.shasums-file: new fetchVerifiedNodeShasums /
  fetchVerifiedNodeShasumsFile verify the signature via openpgp against
  the embedded keys (generated src/nodeReleaseKeys.ts, mirrored from
  the canonical nodejs/release-keys list).
- @pnpm/node.fetcher verifies the configurable-mirror SHASUMS for the
  release channel; pre-release channels (rc, nightly, ...) are unsigned
  by Node and remain unverified.
- scripts/update-node-release-keys.mjs keeps the keys current
  (pnpm run check:node-release-keys / update:node-release-keys), and
  the release workflow runs the check as a gate.

Backport of #12295 to v10 (without the pacquet Rust port,
which does not exist on this branch).
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 16c0ea84-f9d4-42ea-b110-c7240eaafbbd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch backport/v10-security-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0)

Grey Divider


Action required

1. Registry creds leak in errors ✓ Resolved 🐞 Bug ⛨ Security
Description
verifyPnpmEngineIdentity() throws errors that include the full packument URL; if a registry is
configured with embedded basic-auth credentials (e.g. https://user:pass@host/), those secrets can be
printed to terminal/CI logs on non-200 responses.
Code

tools/plugin-commands-self-updater/src/verifyPnpmEngineIdentity.ts[R252-256]

+  if (response.status !== 200) {
+    throw new PnpmError(
+      'ENGINE_IDENTITY_PACKUMENT_FETCH_FAIL',
+      `The packument endpoint (at ${packumentUrl}) responded with ${response.status}: ${await response.text()}`
+    )
Evidence
The thrown error message includes packumentUrl directly. The repo’s auth-header logic explicitly
supports Basic auth embedded in URLs (via URL.username/password), so a configured registry URL can
contain credentials that would be exposed when packumentUrl is printed.

tools/plugin-commands-self-updater/src/verifyPnpmEngineIdentity.ts[235-266]
network/auth-header/src/index.ts[14-53]
network/auth-header/test/getAuthHeaderByURI.ts[24-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`verifyPnpmEngineIdentity()` formats errors that embed `packumentUrl` (derived from registry configuration). Registry URLs can legally include `username:password@` (basic auth), so including the full URL in exception messages may leak credentials to terminal output and CI logs.
### Issue Context
This is triggered on non-200 responses from the packument endpoint, where the code throws a `PnpmError` containing the URL string.
### Fix Focus Areas
- tools/plugin-commands-self-updater/src/verifyPnpmEngineIdentity.ts[239-267]
### Implementation notes
- Before interpolating URLs into error messages, parse with `new URL(...)` and clear `.username` and `.password` (or use an existing redaction helper if present).
- Consider also avoiding inclusion of full `response.text()` in the error message (or truncating/sanitizing it), as it may contain sensitive server-provided details.
- Ensure the redacted URL is used consistently in both the non-200 error and the unexpected-body error.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Bootstrap misses http-proxy 🐞 Bug ☼ Reliability
Description
In getConfig(), packageManager bootstrap network config derives httpProxy from
https-proxy/proxy (or env) but never from a trusted http-proxy setting. This can cause pnpm
version-switch/self-update bootstrap downloads to fail or route incorrectly in environments that
only configure http-proxy.
Code

config/config/src/index.ts[R556-565]

+    const trustedHttpsProxy = getProxyValue(
+      trustedRawConfig['https-proxy'] ?? trustedRawConfig.proxy,
+      getProcessEnv('https_proxy')
+    )
+    pnpmConfig.packageManagerNetworkConfig = {
+      ca: trustedRawConfig.ca as string | string[] | undefined,
+      cert: trustedRawConfig.cert as string | string[] | undefined,
+      httpProxy: trustedHttpsProxy ?? getProcessEnv('http_proxy') ?? getProcessEnv('proxy'),
+      httpsProxy: trustedHttpsProxy,
+      key: trustedRawConfig.key as string | undefined,
Evidence
The bootstrap config only computes trustedHttpsProxy from `trustedRawConfig['https-proxy'] ??
trustedRawConfig.proxy and then sets httpProxy` from that value (or env), never reading
trustedRawConfig['http-proxy']. Nearby code shows regular config populates pnpmConfig.httpProxy
separately when not already set, highlighting the intended separate handling for HTTP vs HTTPS
proxies.

config/config/src/index.ts[541-571]
config/config/src/index.ts[521-526]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`packageManagerNetworkConfig.httpProxy` is computed from `https-proxy`/`proxy` and environment fallbacks, but it never consults `trustedRawConfig['http-proxy']`. This makes bootstrap traffic (version switch/self-update) ignore a user/global `.npmrc` `http-proxy` setting, which can break bootstrap downloads in proxy-restricted environments.
### Issue Context
Regular (non-bootstrap) config supports a distinct `httpProxy` value. Bootstrap config should follow the same precedence rules, but using **trusted** sources only.
### Fix Focus Areas
- Update bootstrap proxy derivation to compute `httpProxy` from `trustedRawConfig['http-proxy']` (and/or `trustedRawConfig.proxy`) with env fallbacks, independently from `httpsProxy`.
- file: `config/config/src/index.ts` — adjust the `packageManagerNetworkConfig` construction.
Fix Focus Areas (exact refs):
- config/config/src/index.ts[541-571]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Backport v10 security hardening for config trust boundaries and binary verification
🐞 Bug fix ✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

Walkthroughs

Description
• Block ${...} env expansion from repo-controlled config in request URLs and credentials.
• Verify signatures before executing downloaded pnpm engines and Node.js runtimes.
• Harden package-manager bootstrap to use only trusted registry/proxy/TLS settings.
Diagram
graph TD
  CLI["pnpm CLI"] --> CFG["getConfig()"] --> SW["switchCliVersion"] --> UPD["self-updater"] --> VER["verify engine"] --> NPM{{"npm registry"}}
  CFG --> DROP["drop untrusted env"]
  CFG --> NODE["node.fetcher"] --> SHAS["verify SHASUMS"] --> MIR{{"Node mirror"}}
  KEYS[("Embedded keys")] --> VER --> NPM
  KEYS --> SHAS --> MIR

  subgraph Legend
    direction LR
    _mod["Module"] ~~~ _data[("Embedded data")] ~~~ _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize verification in a shared workspace package
  • ➕ Reduces duplication if more callers need signature verification
  • ➕ Easier to evolve policy and telemetry in one place
  • ➖ Bigger backport surface for v10; more package wiring and risk
  • ➖ Self-updater is already the natural chokepoint on v10
2. Soft-fail on unreachable registries (warn and continue)
  • ➕ Better offline UX for packageManager version switching
  • ➖ Weakens the security boundary when the trust root is unavailable
  • ➖ Conflicts with explicit 'fail closed' threat model for repo-controlled inputs
3. Defer to external tools (e.g., Corepack) for engine verification
  • ➕ Leverages established implementation and update cadence
  • ➖ Not consistently available/controllable across environments
  • ➖ pnpm still needs enforcement for self-update and repo-driven switches

Recommendation: Keep the PR’s current approach: enforce trust boundaries at config load time and verify binaries at the v10 self-updater staging chokepoint with fail-closed semantics. This minimizes execution of repo-influenced unverified code while keeping performance acceptable (verification only on cache misses) and adds CI gates to prevent key drift.

Grey Divider

File Changes

Enhancement (8)
Config.ts Add package-manager bootstrap network config types +23/-0

Add package-manager bootstrap network config types

• Introduces PackageManagerNetworkConfig and extends Config with packageManagerRegistries and packageManagerNetworkConfig for trusted bootstrap traffic.

config/config/src/Config.ts


index.ts Enforce trust boundary and compute trusted bootstrap config +64/-1

Enforce trust boundary and compute trusted bootstrap config

• Drops untrusted env expansions for project/workspace npm-conf layers and computes packageManager registries/network config from trusted sources only, defaulting to npmjs.

config/config/src/index.ts


index.ts Expose verified SHASUMS fetch and parsing helpers +21/-1

Expose verified SHASUMS fetch and parsing helpers

• Exports fetchVerifiedNodeShasums and adds fetchVerifiedNodeShasumsFile/parseShasumsFile to support signature-verified SHASUMS consumption.

crypto/shasums-file/src/index.ts


nodeReleaseKeys.ts Embed Node.js release OpenPGP public keys (generated) +122/-0

Embed Node.js release OpenPGP public keys (generated)

• Adds a generated, pinned set of Node.js release team public keys used to verify SHASUMS detached signatures.

crypto/shasums-file/src/nodeReleaseKeys.ts


verifyNodeShasums.ts Verify SHASUMS256.txt.sig against embedded Node keys +120/-0

Verify SHASUMS256.txt.sig against embedded Node keys

• Implements detached OpenPGP signature verification and fails when signatures are missing or invalid.

crypto/shasums-file/src/verifyNodeShasums.ts


packageManagerRegistries.ts Add helper to derive bootstrap registries/network config +28/-0

Add helper to derive bootstrap registries/network config

• Introduces helpers to combine default npm registry with trusted bootstrap registries and network settings for version switching.

pnpm/src/packageManagerRegistries.ts


npmSigningKeys.ts Embed npm public signing keys (generated) +29/-0

Embed npm public signing keys (generated)

• Adds a generated, pinned set of npm registry signing keys used as an immutable trust root.

tools/plugin-commands-self-updater/src/npmSigningKeys.ts


verifyPnpmEngineIdentity.ts Corepack-style npm registry signature verification for pnpm engines +343/-0

Corepack-style npm registry signature verification for pnpm engines

• Verifies packument signatures over staged lockfile integrities for pnpm/@pnpm/exe and materialized platform binaries; fails closed on invalid/absent/unreachable registry signatures.

tools/plugin-commands-self-updater/src/verifyPnpmEngineIdentity.ts


Bug fix (6)
dropUntrustedEnvExpansions.ts Drop unsafe env expansions from repo-controlled .npmrc layers +97/-0

Drop unsafe env expansions from repo-controlled .npmrc layers

• Re-reads raw .npmrc without expansion and deletes settings that used ${...} in request destinations or auth values, emitting warnings.

config/config/src/dropUntrustedEnvExpansions.ts


getOptionsFromRootManifest.ts Block env expansion in pnpm-workspace.yaml registry setting +11/-0

Block env expansion in pnpm-workspace.yaml registry setting

• Prevents envReplace from expanding ${...} placeholders in repository-controlled request-destination scalar settings (v10: registry).

config/config/src/getOptionsFromRootManifest.ts


index.ts Verify Node SHASUMS signatures for release-channel downloads +16/-5

Verify Node SHASUMS signatures for release-channel downloads

• Uses fetchVerifiedNodeShasums for the release channel when loading SHASUMS integrity, while leaving prerelease channels unverified; threads releaseChannel option.

env/node.fetcher/src/index.ts


index.ts Reject reserved bin names after scope stripping +7/-1

Reject reserved bin names after scope stripping

• Explicitly rejects empty, '.', and '..' bin names (including scoped forms) that bypassed encodeURIComponent-based validation.

pkg-manager/package-bins/src/index.ts


switchCliVersion.ts Use trusted bootstrap config for version switching installs +8/-1

Use trusted bootstrap config for version switching installs

• Ensures installPnpmToTools receives trusted-only registry/proxy/TLS settings when downloading the pnpm version requested by packageManager.

pnpm/src/switchCliVersion.ts


installPnpmToTools.ts Verify staged pnpm engine identity before linking/spawning +6/-0

Verify staged pnpm engine identity before linking/spawning

• Invokes verifyPnpmEngineIdentity on tools-directory cache misses to fail closed before executing newly downloaded engines.

tools/plugin-commands-self-updater/src/installPnpmToTools.ts


Refactor (4)
downloadNodeVersion.ts Thread Node releaseChannel into node installer calls +2/-1

Thread Node releaseChannel into node installer calls

• Passes releaseChannel through to getNodeDir so node.fetcher can decide whether SHASUMS verification applies.

env/plugin-commands-env/src/downloadNodeVersion.ts


node.ts Propagate releaseChannel to Node directory resolution +2/-1

Propagate releaseChannel to Node directory resolution

• Extends getNodeDir signature and call sites to include releaseChannel for downstream verification decisions.

env/plugin-commands-env/src/node.ts


index.ts Export engine identity verification API +1/-0

Export engine identity verification API

• Exports verifyPnpmEngineIdentity and related types for testing and callers.

tools/plugin-commands-self-updater/src/index.ts


selfUpdate.ts Add test-only trustedKeys option plumbing +5/-1

Add test-only trustedKeys option plumbing

• Extends SelfUpdateCommandOptions with an optional trustedKeys seam so fixtures can skip verification without a runtime off-switch.

tools/plugin-commands-self-updater/src/selfUpdate.ts


Tests (6)
getOptionsFromRootManifest.test.ts Test registry env placeholder blocking in pnpm settings +15/-0

Test registry env placeholder blocking in pnpm settings

• Adds coverage that registry values containing ${...} are ignored while plain registry values are preserved.

config/config/test/getOptionsFromRootManifest.test.ts


index.ts Add trust-boundary tests for .npmrc and bootstrap registries +273/-0

Add trust-boundary tests for .npmrc and bootstrap registries

• Adds extensive tests ensuring repo-controlled .npmrc/workspace config cannot expand env vars into registries/proxies/auth and that bootstrap registries are derived from trusted sources only.

config/config/test/index.ts


verifyNodeShasums.ts Add SHASUMS signature verification tests +66/-0

Add SHASUMS signature verification tests

• Adds tests for valid signatures, untrusted signers, tampering, and missing signature scenarios.

crypto/shasums-file/test/verifyNodeShasums.ts


index.ts Add regression test for reserved bin-name rejection +20/-0

Add regression test for reserved bin-name rejection

• Adds a test asserting reserved bin keys are skipped while valid bin entries are preserved.

pkg-manager/package-bins/test/index.ts


selfUpdate.test.ts Skip signature checks in self-update fixture tests +3/-0

Skip signature checks in self-update fixture tests

• Sets trustedKeys: [] for fixture-based tests where the staged pnpm is not signed with real npm keys.

tools/plugin-commands-self-updater/test/selfUpdate.test.ts


verifyPnpmEngineIdentity.test.ts Add coverage for engine signature verification outcomes +208/-0

Add coverage for engine signature verification outcomes

• Adds tests for valid signatures, tampering, unknown keys, missing versions, unreachable registries, and @pnpm/exe platform package verification.

tools/plugin-commands-self-updater/test/verifyPnpmEngineIdentity.test.ts


Documentation (5)
clean-package-manager-registries.md Document trusted-only bootstrap registries/network config +6/-0

Document trusted-only bootstrap registries/network config

• Adds a changeset explaining that package-manager bootstrap traffic now uses only trusted config layers and defaults to the public npm registry.

.changeset/clean-package-manager-registries.md


pnpm-engine-identity.md Document engine signature verification before spawn +6/-0

Document engine signature verification before spawn

• Adds a changeset describing corepack-style npm registry signature verification for staged pnpm engines, including fail-closed behavior.

.changeset/pnpm-engine-identity.md


sharp-registry-env-placeholders.md Document trust-aware env expansion restrictions +6/-0

Document trust-aware env expansion restrictions

• Adds a changeset describing that repo-controlled config can no longer expand ${...} in registries, proxies, URL-scoped keys, or credentials.

.changeset/sharp-registry-env-placeholders.md


strange-bin-segments.md Document reserved manifest bin-name rejection +6/-0

Document reserved manifest bin-name rejection

• Adds a changeset explaining that reserved/relative bin names are rejected to prevent path-based deletions during global operations.

.changeset/strange-bin-segments.md


verify-node-runtime-shasums.md Document Node SHASUMS OpenPGP verification +8/-0

Document Node SHASUMS OpenPGP verification

• Adds a changeset describing verification of SHASUMS256.txt detached signatures against embedded Node release keys when using mirrors.

.changeset/verify-node-runtime-shasums.md


Other (10)
release.yml Gate releases on embedded key freshness +7/-0

Gate releases on embedded key freshness

• Adds release workflow steps to check embedded npm signing keys and Node.js release keys are in sync with upstream sources.

.github/workflows/release.yml


package.json Add OpenPGP dependencies for SHASUMS verification +3/-1

Add OpenPGP dependencies for SHASUMS verification

• Adds openpgp and @openpgp/web-stream-tools dependencies required to verify detached signatures for Node SHASUMS files.

crypto/shasums-file/package.json


update-node-release-keys.mjs Add script to sync embedded Node.js release keys +94/-0

Add script to sync embedded Node.js release keys

• Introduces a check/update script that mirrors nodejs/release-keys into the repo and fails CI when embedded fingerprints drift.

crypto/shasums-file/scripts/update-node-release-keys.mjs


cspell.json Update dictionary and ignore generated key files +12/-0

Update dictionary and ignore generated key files

• Adds crypto/security terms and ignores generated nodeReleaseKeys files to avoid spellcheck churn.

cspell.json


package.json Add scripts to check/update embedded signing key sets +3/-0

Add scripts to check/update embedded signing key sets

• Adds check/update scripts for Node release keys and npm signing keys, used by the release workflow.

package.json


pnpm-lock.yaml Update lockfile for new OpenPGP deps and workspace changes +119/-46

Update lockfile for new OpenPGP deps and workspace changes

• Adds openpgp/@openpgp/web-stream-tools and updates resolutions impacted by the dependency graph changes.

pnpm-lock.yaml


pnpm-workspace.yaml Add OpenPGP packages to workspace catalog +2/-0

Add OpenPGP packages to workspace catalog

• Adds openpgp and @openpgp/web-stream-tools to the catalog for consistent workspace versioning.

pnpm-workspace.yaml


package.json Add deps required for registry signature verification +6/-0

Add deps required for registry signature verification

• Adds fetch/lockfile/auth/registry-selection dependencies used by verifyPnpmEngineIdentity.

tools/plugin-commands-self-updater/package.json


update-npm-signing-keys.mjs Add script to sync embedded npm signing keys +105/-0

Add script to sync embedded npm signing keys

• Introduces a check/update script that fetches npm signing keys, validates drift in CI, and can regenerate the embedded keys file.

tools/plugin-commands-self-updater/scripts/update-npm-signing-keys.mjs


tsconfig.json Add TS project references for new workspace deps +18/-0

Add TS project references for new workspace deps

• Extends project references to include lockfile/auth/fetch/types and registry selector packages used by the new verifier.

tools/plugin-commands-self-updater/tsconfig.json


Grey Divider

Qodo Logo

The Node.js download tests exercise the release channel, whose
SHASUMS256.txt is now signature-verified. Sign the fixture with a
generated OpenPGP key and trust it through the new
trustedNodeReleaseKeys test seam (threaded from plugin-commands-env via
@pnpm/node.fetcher to fetchVerifiedNodeShasums), so the tests keep
exercising the verification path instead of bypassing it.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 9, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit d7ec2cd

@zkochan

zkochan commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

CI failed in env/plugin-commands-env/test/node.test.ts: two tests download Node from a mocked mirror on the release channel, whose SHASUMS256.txt is now signature-verified, and the fixture was unsigned — so verification correctly rejected it.

Fixed in d7ec2cd by signing the SHASUMS fixture with a generated OpenPGP key and trusting it through a new trustedNodeReleaseKeys test seam (threaded from plugin-commands-env via @pnpm/node.fetcher into fetchVerifiedNodeShasums). The tests keep exercising the verification path instead of bypassing it, mirroring the trustedKeys seam the npm-signature check uses.


Written by an agent (Claude Code, claude-fable-5).

…rrors

Registry URLs may legally embed basic-auth credentials
(https://user:pass@host/). verifyPnpmEngineIdentity() interpolated the
packument URL and registry URL into PnpmError messages, and the
unreachable-registry path surfaced fetch-layer error messages that embed
the request URL — all of which land in terminal output and CI logs.
Strip URL credentials from every error message and truncate the non-200
response body.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 10, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 99e5517

Override shell-quote to >=1.8.4 (GHSA-w7jw-789q-3m8p, critical, pulled
in via concurrently) so the audit workflow passes again. The advisory
was published after the last release/10 audit run; it is unrelated to
the security backports on this branch.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 10, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 2239a3a

@zkochan zkochan merged commit c452019 into release/10 Jun 10, 2026
14 checks passed
@zkochan zkochan deleted the backport/v10-security-fixes branch June 10, 2026 06:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant