Add supply chain queries for npm publish token usage and missing provenance#21621
Add supply chain queries for npm publish token usage and missing provenance#21621david-wiggs wants to merge 1 commit intogithub:mainfrom
Conversation
| command.regexpMatch("(?i).*\\bnpm\\s+publish\\b.*") and | ||
| not command.regexpMatch("(?i).*\\bnpm\\s+publish\\b.*--provenance\\b.*") | ||
| select run, | ||
| "npm publish command does not include '--provenance'. Add '--provenance' to cryptographically link the package to this source commit and workflow run." |
| secretExpr = env.getEnvVarExpr(envVarName) and | ||
| isSecretsReference(secretExpr.getExpression()) | ||
| select secretExpr, | ||
| "Long-lived npm token '$@' is used in a publish step. Use npm Trusted Publishing (OIDC) instead.", |
| isSecretsReference(secretExpr.getExpression()) | ||
| select secretExpr, | ||
| "Long-lived npm token '$@' is used in a publish step. Use npm Trusted Publishing (OIDC) instead.", | ||
| secretExpr, envVarName |
| @@ -0,0 +1 @@ | |||
| Security/CWE-353/MissingProvenanceFlag.ql | |||
| @@ -0,0 +1 @@ | |||
| Security/CWE-798/NpmTokenInPublish.ql | |||
There was a problem hiding this comment.
Pull request overview
Adds two new CodeQL queries to the GitHub Actions pack to detect npm supply-chain risks in workflows: (1) use of long-lived npm publish tokens sourced from secrets, and (2) npm publish commands missing --provenance, along with query help and query-tests.
Changes:
- Added
actions/npm-token-in-publish(CWE-798) to flag publish steps that useNODE_AUTH_TOKEN/NPM_TOKENfromsecrets.*. - Added
actions/missing-provenance-flag(CWE-353) to flagnpm publishcommands missing--provenance. - Added query-tests (workflows +
.qlref+.expected) for both queries.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| actions/ql/src/Security/CWE-798/NpmTokenInPublish.ql | New query to detect long-lived npm tokens used during publish steps. |
| actions/ql/src/Security/CWE-798/NpmTokenInPublish.md | Query help documenting risk + OIDC Trusted Publishing remediation guidance. |
| actions/ql/src/Security/CWE-353/MissingProvenanceFlag.ql | New query to detect npm publish without --provenance. |
| actions/ql/src/Security/CWE-353/MissingProvenanceFlag.md | Query help documenting provenance attestation and recommended workflow permissions. |
| actions/ql/test/query-tests/Security/CWE-798/NpmTokenInPublish.qlref | Registers the CWE-798 query for query-tests. |
| actions/ql/test/query-tests/Security/CWE-798/NpmTokenInPublish.expected | Expected results for npm-token-in-publish query-tests. |
| actions/ql/test/query-tests/Security/CWE-798/.github/workflows/npm-token-publish.yml | Positive test workflow cases for token-in-publish detections. |
| actions/ql/test/query-tests/Security/CWE-798/.github/workflows/npm-token-publish-safe.yml | Negative test workflow cases for token-in-publish. |
| actions/ql/test/query-tests/Security/CWE-353/MissingProvenanceFlag.qlref | Registers the CWE-353 query for query-tests. |
| actions/ql/test/query-tests/Security/CWE-353/MissingProvenanceFlag.expected | Expected results for missing-provenance-flag query-tests. |
| actions/ql/test/query-tests/Security/CWE-353/.github/workflows/npm-publish-with-provenance.yml | Negative test workflow cases (has --provenance). |
| actions/ql/test/query-tests/Security/CWE-353/.github/workflows/npm-publish-no-provenance.yml | Positive test workflow cases (missing --provenance). |
Comments suppressed due to low confidence (1)
actions/ql/src/Security/CWE-798/NpmTokenInPublish.md:7
- The recommendation only mentions removing
NODE_AUTH_TOKEN, but the query (and overview) also coversNPM_TOKEN. Consider updating the recommendation to cover both env vars / long-lived npm tokens in general.
Remove `NODE_AUTH_TOKEN` from the publish step. Configure npm Trusted Publishing (OIDC) on npmjs.com, pointing to this repository and workflow. This eliminates the need for long-lived tokens entirely.
| @@ -0,0 +1,54 @@ | |||
| /** | |||
| * @name Long-lived npm token used in publish step | |||
| * @description The publish step sets NODE_AUTH_TOKEN or NPM_TOKEN from a repository secret. | |||
There was a problem hiding this comment.
The query help text says the token is sourced from a "repository secret", but this query matches any secrets.* reference (which may be repository, environment, or organization). Consider rewording to "a GitHub Actions secret" (or similar) to avoid being misleading.
| * @description The publish step sets NODE_AUTH_TOKEN or NPM_TOKEN from a repository secret. | |
| * @description The publish step sets NODE_AUTH_TOKEN or NPM_TOKEN from a GitHub Actions secret. |
| @@ -0,0 +1,35 @@ | |||
| ## Overview | |||
|
|
|||
| The publish step sets `NODE_AUTH_TOKEN` (or `NPM_TOKEN`) from a repository secret. This is a long-lived credential that can be stolen and used to publish malicious versions from outside the CI/CD pipeline, as demonstrated by the axios@1.14.1 supply chain attack. | |||
There was a problem hiding this comment.
This overview states the token comes from a "repository secret", but the secret context also includes environment/org secrets. Consider using more accurate wording like "a GitHub Actions secret (secrets.*)".
This issue also appears on line 7 of the same file.
| The publish step sets `NODE_AUTH_TOKEN` (or `NPM_TOKEN`) from a repository secret. This is a long-lived credential that can be stolen and used to publish malicious versions from outside the CI/CD pipeline, as demonstrated by the axios@1.14.1 supply chain attack. | |
| The publish step sets `NODE_AUTH_TOKEN` (or `NPM_TOKEN`) from a GitHub Actions secret (`secrets.*`). This is a long-lived credential that can be stolen and used to publish malicious versions from outside the CI/CD pipeline, as demonstrated by the axios@1.14.1 supply chain attack. |
|
@copilot apply changes based on the comments in this thread |
Description
Adds two new CodeQL queries for GitHub Actions workflows that detect npm supply chain security risks:
New Queries
actions/npm-token-in-publish(CWE-798, error, severity 9.0)Detects publish steps (
npm publish,yarn publish,JS-DevTools/npm-publish) that setNODE_AUTH_TOKENorNPM_TOKENfrom a repository secret. Long-lived npm tokens can be stolen and used to publish malicious package versions from outside the CI/CD pipeline (e.g. the axios@1.14.1 attack). The recommended remediation is to use npm Trusted Publishing (OIDC).actions/missing-provenance-flag(CWE-353, warning, severity 5.0)Detects
npm publishcommands that do not include the--provenanceflag. Provenance attestation cryptographically links the published package to a specific source commit and workflow run.Files Added
actions/ql/src/Security/CWE-798/NpmTokenInPublish.ql+.mdactions/ql/src/Security/CWE-353/MissingProvenanceFlag.ql+.md.qlref, and.expectedfiles for both queries