CI: pin actions to commit SHAs and declare workflow permissions - #3881
Open
Totara-thib wants to merge 2 commits into
Open
CI: pin actions to commit SHAs and declare workflow permissions#3881Totara-thib wants to merge 2 commits into
Totara-thib wants to merge 2 commits into
Conversation
A tag like @v2 or a branch like @master is a movable pointer: whoever controls the action repository can re-point it, and the next run executes whatever it points at with the job's credentials. The paths that matter here: the build job publishes the release archives people download with a contents write token, and the winget job holds WINGET_TOKEN. This is exactly how the tj-actions/changed-files compromise spread (CVE-2025-30066). winget-releaser is already pinned by sha, this finishes the job in the same spirit for checkout, upload-artifact and rust-toolchain. rust-toolchain's tags are toolchain names, so every site is pinned to the same master commit and the toolchain moves to an explicit 'toolchain:' input (stable where the tag implied it, the msrv site already had one), zero behavior change. Dependabot's github-actions ecosystem is already configured here, so it keeps bumping the pins with the comments in sync. Every sha was resolved from the upstream repository and cross-checked against its release tag.
Jobs without a permissions block inherit the repository default token scope, and most of these jobs run pull request code while holding that token. Scopes are derived from what each job actually does: everything drops to contents: read, except the build job, which keeps contents: write to publish the release archives on tag builds. The winget job pushes with its own dedicated token and the changelog check reads the public API unauthenticated, so both need nothing.
Totara-thib
force-pushed
the
ci-hardening
branch
from
August 6, 2026 08:20
006b3ac to
a3c6d45
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hi, drive-by CI hardening in two commits, one logical change each, found with the Plumber CLI (https://github.com/getplumber/plumber) and verified on master.
Commit 1 pins every action to its commit sha, versions kept as comments. A tag like @v2 or a branch like @master is a movable pointer: whoever controls the action, or anyone who compromises it, can re-point it and your next run executes their code with the job's credentials. The paths that matter here: the build job publishes the release archives people download while holding a contents write token, and the winget job runs with WINGET_TOKEN. Same pattern as the tj-actions/changed-files incident (CVE-2025-30066). You already pin winget-releaser by sha, this finishes the job in the same spirit. rust-toolchain's tags are toolchain names, so all six sites point at the same master commit and the toolchain moves to an explicit toolchain: input (stable where the tag implied it, your msrv site already had one), zero behavior change. Your dependabot config already covers the github-actions ecosystem, so the pins keep themselves bumped with the comments in sync.
Commit 2 scopes the GITHUB_TOKEN per workflow, derived from what each job actually uses: everything drops to contents: read, except the build job which keeps contents: write to publish the release archives on tag builds. The winget job pushes with its own token and the changelog check reads the public API unauthenticated, so neither needs anything.
One heads up: if an Actions allowlist is configured in settings, patterns written against tags (like owner/action@v2) stop matching once refs are shas and workflows refuse to start. Entries need the owner/action@* form.
A CHANGELOG entry is included per CONTRIBUTING. I will also open a PR which adds the tool to CI so this does not quietly drift back; that one is a bonus, this PR stands on its own.