Skip to content

fix(ci): harden GitHub Actions workflows (#14789) - #14793

Closed
hf-security-analysis[bot] wants to merge 0 commit into
dependabot/github_actions/actions-ca6b5df6adfrom
security/workflow-hardening/pr-14789
Closed

hf-security-analysis[bot] wants to merge 0 commit into
dependabot/github_actions/actions-ca6b5df6adfrom
security/workflow-hardening/pr-14789

Conversation

@hf-security-analysis

@hf-security-analysis hf-security-analysis Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

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

Fixed by this PR:

  • HIGH broken_auth_gate (claude) — .github/workflows/bot_pytest.yml
  • HIGH unpinned-action (pinact) — .github/workflows/bot_pytest.yml:78
  • HIGH unpinned-action (pinact) — .github/workflows/bot_pytest.yml:119
  • HIGH excessive-permissions (zizmor) — .github/workflows/claude_review.yml:10
  • HIGH excessive-permissions (zizmor) — .github/workflows/claude_review.yml:11
  • HIGH unpinned-action (pinact) — .github/workflows/claude_review.yml:37
  • HIGH llm_prompt_injection (claude) — .github/workflows/issue_labeler.yml
  • HIGH excessive-permissions (zizmor) — .github/workflows/issue_labeler.yml:9
  • HIGH unpinned-action (pinact) — .github/workflows/mirror_community_pipeline.yml:72
  • HIGH unpinned-action (pinact) — .github/workflows/mirror_community_pipeline.yml:78
  • HIGH unpinned-action (pinact) — .github/workflows/notify_slack_about_release.yml:16
  • HIGH unpinned-action (pinact) — .github/workflows/notify_slack_about_release.yml:19
  • HIGH unpinned-action (pinact) — .github/workflows/pr_dependency_test.yml:25
  • HIGH unpinned-action (pinact) — .github/workflows/pr_dependency_test.yml:27
  • HIGH dangerous-triggers (zizmor) — .github/workflows/pr_labeler.yml:3
  • HIGH excessive-permissions (zizmor) — .github/workflows/pr_labeler.yml:9
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:47
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:49
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:67
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:69
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:95
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:125
  • HIGH unpinned-action (pinact) — .github/workflows/pr_modular_tests.yml:154
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:34
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:48
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:89
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:115
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:144
  • HIGH unpinned-action (pinact) — .github/workflows/pr_test_fetcher.yml:170
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:42
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:44
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:62
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:64
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:122
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:166
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:198
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:226
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:252
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests.yml:293
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:43
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:45
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:63
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:65
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:95
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:113
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:133
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:182
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:205
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:251
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:267
  • HIGH unpinned-action (pinact) — .github/workflows/pr_tests_gpu.yml:299
  • HIGH unpinned-action (pinact) — .github/workflows/pr_torch_dependency_test.yml:25
  • HIGH unpinned-action (pinact) — .github/workflows/pr_torch_dependency_test.yml:27
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:40
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:58
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:78
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:109
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:131
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:166
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:183
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:209
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:226
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:251
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:267
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests.yml:298
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests_fast.yml:63
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests_fast.yml:96
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests_mps.yml:29
  • HIGH unpinned-action (pinact) — .github/workflows/push_tests_mps.yml:71
  • HIGH unpinned-action (pinact) — .github/workflows/pypi_publish.yaml:75
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:39
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:58
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:78
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:109
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:131
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:166
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:183
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:223
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:240
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:266
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:283
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:309
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:326
  • HIGH unpinned-action (pinact) — .github/workflows/release_tests_fast.yml:359
  • HIGH unpinned-action (pinact) — .github/workflows/ssh-runner.yml:41
  • HIGH unpinned-action (pinact) — .github/workflows/stale.yml:18
  • HIGH unpinned-action (pinact) — .github/workflows/stale.yml:21
  • HIGH unpinned-action (pinact) — .github/workflows/trufflehog.yml:18
  • HIGH unpinned-action (pinact) — .github/workflows/update_metadata.yml:21

This does not fix everything. 43 further finding(s) (39 high, 4 medium) need a decision this bot should not make for you. They are in the security channel with their locations — deliberately not repeated here, since this repository may be public and they are not fixed yet.

Permissions

.github/workflows/bot_pytest.yml

job granted why
gate issues: write, pull-requests: write The "Acknowledge with 👀" and "Post 'running' comment" steps POST to the literal repos/$REPO/issues/comments/$ID/reactions and repos/$REPO/issues/$PR/comments endpoints, which is comment-write on a PR conversation (pull-requests: write); issues: write is included because the calls go through the /issues/ comment endpoints and would be needed if the command is ever invoked on a plain issue — reviewers can drop it if usage is PR-only.
gpu contents: read Only actions/checkout of refs/pull/<n>/head needs the token (contents: read); the pytest/dependency steps use no API and actions/upload-artifact within the same run needs no scope.
report issues: write, pull-requests: write The "Update comment with final status" step PATCHes repos/$REPO/issues/comments/$CID, i.e. editing a comment on the PR thread (pull-requests: write); issues: write is added only because the call uses the /issues/ comment endpoint and can be removed if the bot is PR-only.

.github/workflows/claude_review.yml

job granted why
claude-review contents: write, issues: read, pull-requests: write The final "Open follow-up PR with Claude's changes" step pushes new branches (git push origin), runs gh pr create and gh pr comment, which drives contents: write plus pull-requests: write; checkout and gh pr view need only read, and issues: read covers reading the triggering issue comment — the step I was least sure about is anthropics/claude-code-action, which in some configurations also wants issues: write (to post/update its tracking comment) and id-token: write, so check that one if the run fails.

.github/workflows/codeql.yml

codeql was left as it is — This job only delegates to the external reusable workflow huggingface/security-workflows/.github/workflows/codeql-reusable.yml (pinned to a SHA), whose steps are not visible in this file, so its true token needs cannot be verified here; the already-declared set (security-events: write for SARIF upload, plus actions/contents/packages read) is consistent with a standard CodeQL scan and should be checked against that reusable workflow.

.github/workflows/issue_labeler.yml

job granted why
label contents: read, issues: write actions/checkout needs contents: read, and the "Apply labels" step runs gh issue edit --add-label with GITHUB_TOKEN, requiring issues: 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 issue title/body — no GITHUB_TOKEN — so it cannot use the repo token.

.github/workflows/pr_labeler.yml

job granted why
label contents: read, pull-requests: write actions/labeler applies/removes labels on the PR (pull-requests: write) and reads its .github/labeler.yml config from the repo via the API (contents: read); sync-labels only widens label removal, not the scopes.
missing-tests contents: read, issues: read, pull-requests: write actions/checkout needs contents: read and the final step's gh pr edit --add-label/--remove-label needs pull-requests: write; the GET on repos//issues//labels is read-only, and note that utils/check_test_missing.py is not in this file (it only consumes piped JSON here, but a reviewer should confirm it makes no other API calls with GH_TOKEN).
fixes-issue issues: read, pull-requests: write gh pr edit --add-label/--remove-label drives pull-requests: write; the GraphQL query only reads PR/closing-issue metadata and the raw gh api repos/*/issues/*/labels call is a GET, hence issues: read.
size-label issues: read, pull-requests: write gh pr edit --add-label/--remove-label for the size/* labels requires pull-requests: write; the gh api repos/*/pulls/* and repos/*/issues/*/labels calls are read-only.

.github/workflows/pr_link_issue_reminder.yml

remind was left as it is — The only meaningful step runs python utils/remind_link_issue.py, a script not included in this file, so its exact API calls cannot be verified; based on the job's stated behavior (commenting on PRs, adding/checking the no-issue-needed label, closing PRs) the needed set is most likely contents: read for actions/checkout plus pull-requests: write and issues: write — please confirm against the script.

.github/workflows/stale.yml

job granted why
close_stale_issues contents: read, issues: write, pull-requests: write actions/checkout drives contents: read, and the final step runs utils/stale.py (PyGithub) which comments on/closes stale issues and PRs — that script's contents are not in this file, so the issues: write and pull-requests: write scopes are inferred from its name plus the job's own declared permissions and are the ones to verify.

Anything not listed above keeps the permissions it had. To measure a job this could not read, add GitHubSecurityLab/actions-permissions/monitor to it and run the workflow — it reports the minimum the run actually used.

Pinning changes come from pinact and are mechanical. Any other change was generated by Claude — read it before merging.

@github-actions github-actions Bot added CI size/L PR with diff > 200 LOC labels Sep 16, 2026
@dependabot
dependabot Bot force-pushed the dependabot/github_actions/actions-ca6b5df6ad branch 2 times, most recently from e801a34 to e6be245 Compare September 17, 2026 12:08
@hf-security-analysis
hf-security-analysis Bot force-pushed the security/workflow-hardening/pr-14789 branch from 73af81c to e801a34 Compare September 17, 2026 12:08
@hf-security-analysis
hf-security-analysis Bot force-pushed the security/workflow-hardening/pr-14789 branch from bb2f1dc to e6be245 Compare September 17, 2026 12:14
@github-actions github-actions Bot added size/S PR with diff < 50 LOC and removed size/L PR with diff > 200 LOC labels Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI size/S PR with diff < 50 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants