From 478224495a5c32286599233e85448a03f042549c Mon Sep 17 00:00:00 2001 From: Salah-Eddine Saakoun Date: Tue, 17 Mar 2026 16:07:32 +0100 Subject: [PATCH 1/2] fix: sanitize .yarnrc.yml scoped registry overrides in publish-preview YARN_NPM_REGISTRY_SERVER only overrides the global npmRegistryServer. Scoped registries (npmScopes..npmRegistryServer) take precedence, allowing a malicious PR to redirect yarn npm publish to an attacker server and exfiltrate the NPM token. Strip both npmRegistryServer and npmScopes from .yarnrc.yml before publishing. --- .github/workflows/publish-preview.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/publish-preview.yml b/.github/workflows/publish-preview.yml index 60236360..fc6dd0e0 100644 --- a/.github/workflows/publish-preview.yml +++ b/.github/workflows/publish-preview.yml @@ -213,6 +213,13 @@ jobs: echo "::error::No package.json files found to validate" exit 1 fi + # Strip registry overrides from .yarnrc.yml to prevent scoped + # registry redirects (npmScopes..npmRegistryServer) which + # take precedence over the YARN_NPM_REGISTRY_SERVER env var. + if [[ -f .yarnrc.yml ]]; then + echo "Stripping registry config from .yarnrc.yml" + yq -i 'del(.npmRegistryServer) | del(.npmScopes)' .yarnrc.yml + fi for f in "${manifests[@]}"; do # Strip lifecycle scripts that run during pack/publish if jq -e '.scripts // {} | keys[] | select(test("^(pre|post)?(pack|publish|prepare)$"))' "$f" > /dev/null 2>&1; then From e8126ace58a71b570b29d10f07e4e69717f71416 Mon Sep 17 00:00:00 2001 From: Salah-Eddine Saakoun Date: Tue, 17 Mar 2026 16:20:30 +0100 Subject: [PATCH 2/2] fix: also strip npmPublishRegistry from .yarnrc.yml npmPublishRegistry takes precedence over npmRegistryServer for yarn npm publish, bypassing the YARN_NPM_REGISTRY_SERVER env var. --- .github/workflows/publish-preview.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-preview.yml b/.github/workflows/publish-preview.yml index fc6dd0e0..405ed732 100644 --- a/.github/workflows/publish-preview.yml +++ b/.github/workflows/publish-preview.yml @@ -213,12 +213,14 @@ jobs: echo "::error::No package.json files found to validate" exit 1 fi - # Strip registry overrides from .yarnrc.yml to prevent scoped - # registry redirects (npmScopes..npmRegistryServer) which - # take precedence over the YARN_NPM_REGISTRY_SERVER env var. + # Strip registry overrides from .yarnrc.yml to prevent registry + # redirects that could exfiltrate the NPM token. npmPublishRegistry + # takes precedence over npmRegistryServer for yarn npm publish, and + # npmScopes can override per-scope. YARN_NPM_REGISTRY_SERVER env var + # only overrides npmRegistryServer, not the others. if [[ -f .yarnrc.yml ]]; then echo "Stripping registry config from .yarnrc.yml" - yq -i 'del(.npmRegistryServer) | del(.npmScopes)' .yarnrc.yml + yq -i 'del(.npmRegistryServer) | del(.npmPublishRegistry) | del(.npmScopes)' .yarnrc.yml fi for f in "${manifests[@]}"; do # Strip lifecycle scripts that run during pack/publish