From 0c442c847a4c878d6d23528ab1e65253bceb3c2e Mon Sep 17 00:00:00 2001 From: Petr Pucil Date: Wed, 8 Apr 2026 22:40:14 +0200 Subject: [PATCH] Prevent cache poisoning vuln in GitHub Actions sample workflows The PR https://github.com/npm/documentation/pull/1917 bumped the `actions/setup-node` action from v4 to v6. This made the publishing GitHub Actions sample workflows potentially vulnerable to cache poisoning, because v5 and later enable caching by default (see https://github.com/actions/setup-node/blob/53b83947a5a98c8d113130e565377fae1a50d02f/README.md#breaking-changes-in-v5). v6 only enables automatic caching if the `packageManager` field in package.json is set to `npm`. Consuming GitHub Actions cache in publishing workflows is discouraged, because the cache may be poisoned by compromising any low-privileged workflow in the same repository. Normally, a code injection vulnerability in a low-privileged workflow (for example `permissions: {contents: read}` and no secrets) is not a big deal, because the attacker cannot do much more than poison the repository cache (which requires no permissions). If caching is only used in other low-privileged workflows, the impact is limited. However, if a high-privileged workflow like the release build consumes the cache, then it becomes a real problem. As @AdnaneKhan concludes in his blog posts about GitHub Actions cache poisoning, such as https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/#dont-use-actions-caching-in-release-builds: "the best way to protect the integrity of releases is to avoid using GitHub Actions caching entirely for release workflows." The README of `actions/setup-node` also recommends `package-manager-cache: false` for privileged workflows (see https://github.com/actions/setup-node/blob/53b83947a5a98c8d113130e565377fae1a50d02f/README.md#breaking-changes-in-v5): > For workflows with elevated privileges or access to sensitive > information, we recommend disabling automatic caching by setting > `package-manager-cache: false` when caching is not needed for secure > operation. --- .../generating-provenance-statements.mdx | 7 ++++--- .../securing-your-code/trusted-publishers.mdx | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/content/packages-and-modules/securing-your-code/generating-provenance-statements.mdx b/content/packages-and-modules/securing-your-code/generating-provenance-statements.mdx index a4dbc2f2041..6c065d3de5c 100644 --- a/content/packages-and-modules/securing-your-code/generating-provenance-statements.mdx +++ b/content/packages-and-modules/securing-your-code/generating-provenance-statements.mdx @@ -91,11 +91,12 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: - node-version: '20.x' + node-version: '24.x' registry-url: 'https://registry.npmjs.org' + package-manager-cache: false # never use caching in release builds - run: npm ci - run: npm publish --provenance --access public env: diff --git a/content/packages-and-modules/securing-your-code/trusted-publishers.mdx b/content/packages-and-modules/securing-your-code/trusted-publishers.mdx index 557c9bdbc0c..4c52609b4d5 100644 --- a/content/packages-and-modules/securing-your-code/trusted-publishers.mdx +++ b/content/packages-and-modules/securing-your-code/trusted-publishers.mdx @@ -106,6 +106,7 @@ jobs: with: node-version: '24' registry-url: 'https://registry.npmjs.org' + package-manager-cache: false # never use caching in release builds - run: npm ci - run: npm run build --if-present - run: npm test @@ -298,10 +299,11 @@ While trusted publishing handles the publish operation, you may still need authe ```yaml # GitHub Actions example -- uses: actions/setup-node@v4 +- uses: actions/setup-node@v6 with: node-version: '24' registry-url: 'https://registry.npmjs.org' + package-manager-cache: false # never use caching in release builds # Use a read-only token for installing dependencies - run: npm ci env: