fix(ci): harden GitHub Actions workflows (#14789) - #14790
Closed
hf-security-analysis[bot] wants to merge 0 commit into
Closed
hf-security-analysis[bot] wants to merge 0 commit into
hf-security-analysis[bot] wants to merge 0 commit into
Conversation
dependabot
Bot
force-pushed
the
dependabot/github_actions/actions-ca6b5df6ad
branch
from
September 16, 2026 15:06
f642106 to
d822ec1
Compare
hf-security-analysis
Bot
force-pushed
the
security/workflow-hardening/pr-14789
branch
from
September 16, 2026 15:13
9eda11d to
d822ec1
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.
Automated hardening of the workflow files flagged on #14789.
Warning
This changes when the workflow runs and what it can reach. Both triggers and permissions were rewritten in
.github/workflows/claude_review.yml,.github/workflows/issue_labeler.yml,.github/workflows/pr_labeler.yml. Read the diff before merging — either one can change what the workflow is able to do.Targets
dependabot/github_actions/actions-ca6b5df6ad. Files changed:.github/workflows/benchmark.yml.github/workflows/bot_pytest.yml.github/workflows/claude_review.yml.github/workflows/issue_labeler.yml.github/workflows/mirror_community_pipeline.yml.github/workflows/notify_slack_about_release.yml.github/workflows/pr_dependency_test.yml.github/workflows/pr_labeler.yml.github/workflows/pr_modular_tests.yml.github/workflows/pr_test_fetcher.yml.github/workflows/pr_tests.yml.github/workflows/pr_tests_gpu.yml.github/workflows/pr_torch_dependency_test.yml.github/workflows/push_tests.yml.github/workflows/push_tests_fast.yml.github/workflows/push_tests_mps.yml.github/workflows/pypi_publish.yaml.github/workflows/release_tests_fast.yml.github/workflows/ssh-runner.yml.github/workflows/stale.yml.github/workflows/trufflehog.yml.github/workflows/update_metadata.yml.github/workflows/upload_pr_documentation.ymlFixed by this PR:
broken_auth_gate(claude) — .github/workflows/bot_pytest.ymlunpinned-action(pinact) — .github/workflows/bot_pytest.yml:78unpinned-action(pinact) — .github/workflows/bot_pytest.yml:119excessive-permissions(zizmor) — .github/workflows/claude_review.yml:10excessive-permissions(zizmor) — .github/workflows/claude_review.yml:11unpinned-action(pinact) — .github/workflows/claude_review.yml:37llm_prompt_injection(claude) — .github/workflows/issue_labeler.ymlexcessive-permissions(zizmor) — .github/workflows/issue_labeler.yml:9unpinned-action(pinact) — .github/workflows/mirror_community_pipeline.yml:72unpinned-action(pinact) — .github/workflows/mirror_community_pipeline.yml:78unpinned-action(pinact) — .github/workflows/notify_slack_about_release.yml:16unpinned-action(pinact) — .github/workflows/notify_slack_about_release.yml:19unpinned-action(pinact) — .github/workflows/pr_dependency_test.yml:25unpinned-action(pinact) — .github/workflows/pr_dependency_test.yml:27dangerous-triggers(zizmor) — .github/workflows/pr_labeler.yml:3excessive-permissions(zizmor) — .github/workflows/pr_labeler.yml:9unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:47unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:49unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:67unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:69unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:95unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:125unpinned-action(pinact) — .github/workflows/pr_modular_tests.yml:154unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:34unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:48unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:89unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:115unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:144unpinned-action(pinact) — .github/workflows/pr_test_fetcher.yml:170unpinned-action(pinact) — .github/workflows/pr_tests.yml:42unpinned-action(pinact) — .github/workflows/pr_tests.yml:44unpinned-action(pinact) — .github/workflows/pr_tests.yml:62unpinned-action(pinact) — .github/workflows/pr_tests.yml:64unpinned-action(pinact) — .github/workflows/pr_tests.yml:122unpinned-action(pinact) — .github/workflows/pr_tests.yml:166unpinned-action(pinact) — .github/workflows/pr_tests.yml:198unpinned-action(pinact) — .github/workflows/pr_tests.yml:226unpinned-action(pinact) — .github/workflows/pr_tests.yml:252unpinned-action(pinact) — .github/workflows/pr_tests.yml:293unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:43unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:45unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:63unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:65unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:95unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:113unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:133unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:182unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:205unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:251unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:267unpinned-action(pinact) — .github/workflows/pr_tests_gpu.yml:299unpinned-action(pinact) — .github/workflows/pr_torch_dependency_test.yml:25unpinned-action(pinact) — .github/workflows/pr_torch_dependency_test.yml:27unpinned-action(pinact) — .github/workflows/push_tests.yml:40unpinned-action(pinact) — .github/workflows/push_tests.yml:58unpinned-action(pinact) — .github/workflows/push_tests.yml:78unpinned-action(pinact) — .github/workflows/push_tests.yml:109unpinned-action(pinact) — .github/workflows/push_tests.yml:131unpinned-action(pinact) — .github/workflows/push_tests.yml:166unpinned-action(pinact) — .github/workflows/push_tests.yml:183unpinned-action(pinact) — .github/workflows/push_tests.yml:209unpinned-action(pinact) — .github/workflows/push_tests.yml:226unpinned-action(pinact) — .github/workflows/push_tests.yml:251unpinned-action(pinact) — .github/workflows/push_tests.yml:267unpinned-action(pinact) — .github/workflows/push_tests.yml:298unpinned-action(pinact) — .github/workflows/push_tests_fast.yml:63unpinned-action(pinact) — .github/workflows/push_tests_fast.yml:96unpinned-action(pinact) — .github/workflows/push_tests_mps.yml:29unpinned-action(pinact) — .github/workflows/push_tests_mps.yml:71unpinned-action(pinact) — .github/workflows/pypi_publish.yaml:75unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:39unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:58unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:78unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:109unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:131unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:166unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:183unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:223unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:240unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:266unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:283unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:309unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:326unpinned-action(pinact) — .github/workflows/release_tests_fast.yml:359unpinned-action(pinact) — .github/workflows/ssh-runner.yml:41unpinned-action(pinact) — .github/workflows/stale.yml:18unpinned-action(pinact) — .github/workflows/stale.yml:21unpinned-action(pinact) — .github/workflows/trufflehog.yml:18unpinned-action(pinact) — .github/workflows/update_metadata.yml:21Reported on the pull request but not fixed here — each needs a decision this bot should not make for you:
unpinned-images(zizmor) — .github/workflows/benchmark.yml:30unpinned-images(zizmor) — .github/workflows/bot_pytest.yml:57unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:34unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:71unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:117unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:189unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:233unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:282unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:356unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:412unpinned-images(zizmor) — .github/workflows/nightly_tests.yml:470unpinned-images(zizmor) — .github/workflows/pr_modular_tests.yml:93unpinned-images(zizmor) — .github/workflows/pr_modular_tests.yml:116unpinned-images(zizmor) — .github/workflows/pr_test_fetcher.yml:24unpinned-images(zizmor) — .github/workflows/pr_test_fetcher.yml:82unpinned-images(zizmor) — .github/workflows/pr_test_fetcher.yml:135unpinned-images(zizmor) — .github/workflows/pr_tests.yml:110unpinned-images(zizmor) — .github/workflows/pr_tests.yml:189unpinned-images(zizmor) — .github/workflows/pr_tests.yml:240unpinned-images(zizmor) — .github/workflows/pr_tests_gpu.yml:90unpinned-images(zizmor) — .github/workflows/pr_tests_gpu.yml:129unpinned-images(zizmor) — .github/workflows/pr_tests_gpu.yml:193unpinned-images(zizmor) — .github/workflows/pr_tests_gpu.yml:263unpinned-images(zizmor) — .github/workflows/push_tests.yml:35unpinned-images(zizmor) — .github/workflows/push_tests.yml:74unpinned-images(zizmor) — .github/workflows/push_tests.yml:119unpinned-images(zizmor) — .github/workflows/push_tests.yml:178unpinned-images(zizmor) — .github/workflows/push_tests.yml:221unpinned-images(zizmor) — .github/workflows/push_tests.yml:263unpinned-images(zizmor) — .github/workflows/push_tests_fast.yml:51unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:34unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:74unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:119unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:176unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:235unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:278unpinned-images(zizmor) — .github/workflows/release_tests_fast.yml:321unpinnable-reference(pinact) — .github/workflows/ssh-runner.yml:50dangerous-triggers(zizmor) — .github/workflows/upload_pr_documentation.yml:3excessive-permissions(zizmor) — .github/workflows/bot_pytest.yml:1excessive-permissions(zizmor) — .github/workflows/codeql.yml:2excessive-permissions(zizmor) — .github/workflows/pr_link_issue_reminder.yml:1excessive-permissions(zizmor) — .github/workflows/stale.yml:1Permissions
.github/workflows/bot_pytest.ymlgateissues: write,pull-requests: writegh api -X POSTcalls hit literal endpointsrepos/{repo}/issues/comments/{id}/reactionsandrepos/{repo}/issues/{pr}/comments, i.e. it writes a reaction and a comment on the PR;pull-requests: writecovers PR comments, andissues: writeis included because the reaction/comment calls go through the issues-comments API surface — a reviewer may dropissuesif reactions succeed with onlypull-requests: write.gpucontents: readactions/checkoutof the PR head needs the token (contents: read); the dependency installs, pytest run andactions/upload-artifact(same-run upload) need no token scopes.reportissues: write,pull-requests: writegh api -X PATCH repos/{repo}/issues/comments/{id}to edit the bot's PR comment, which needs comment write access —pull-requests: writefor a PR conversation comment, withissues: writeincluded since the call uses the issues-comments endpoint..github/workflows/claude_review.ymlclaude-reviewcontents: write,issues: read,pull-requests: writegit push origin) and runsgh pr create/gh pr comment, requiring contents: write and pull-requests: write;gh pr viewonly needs read, and issues: read covers the claude-code-action reading the triggering issue comment context — that third-party action (anthropics/claude-code-action) is the step I was least able to verify, and some setups also add id-token: write for it, which I omitted since the workflow's own declared permissions do not include it..github/workflows/codeql.yml.github/workflows/issue_labeler.ymllabelcontents: read,issues: writeactions/checkoutneedscontents: read, and the "Apply labels" step runsgh issue edit --add-labelwith GITHUB_TOKEN, which requiresissues: write; the "Get labels from LLM" step runs utils/label_issues.py, which is not in this file, but it is only given HF_TOKEN and no GitHub token, so it should need no scope — worth a glance during review..github/workflows/pr_labeler.ymllabelcontents: read,pull-requests: writemissing-testscontents: read,issues: read,pull-requests: writegh api repos/.../pulls/N/filescall needs pull-request read, thegh api repos/.../issues/N/labelsread is an issues endpoint (issues: read), andgh pr edit --add-label/--remove-labelrequires pull-requests: write; the piped utils/check_test_missing.py only consumes stdin and needs no token.fixes-issueissues: read,pull-requests: writegh pr edit --add-label/--remove-labeldrives pull-requests: write; thegh api repos/.../issues/N/labelsread accounts for issues: read.size-labelissues: read,pull-requests: writegh api(pull-request read plus issues: read for the issues/labels endpoint) and applies size labels withgh pr edit --add-label/--remove-label, which needs pull-requests: write..github/workflows/pr_link_issue_reminder.yml.github/workflows/stale.ymlclose_stale_issuescontents: read,issues: write,pull-requests: writeactions/checkoutneedscontents: read, and the final step runspython utils/stale.pywithGITHUB_TOKENvia PyGithub to comment on/close stale issues and pull requests, soissues: writeandpull-requests: writeare required; the script body is not in this file, so a reviewer should confirm utils/stale.py does not also touch other APIs (e.g. labels on other resources or repo contents).Anything not listed above keeps the permissions it had. To measure a job this could not read, add
GitHubSecurityLab/actions-permissions/monitorto it and run the workflow — it reports the minimum the run actually used.Pinning changes come from
pinactand are mechanical. Any other change was generated by Claude — read it before merging.