Skip to content

Apply least-privilege permissions to CI workflows#193

Merged
mclasmeier merged 1 commit into
mainfrom
mc/workflow-perm-hardening
May 18, 2026
Merged

Apply least-privilege permissions to CI workflows#193
mclasmeier merged 1 commit into
mainfrom
mc/workflow-perm-hardening

Conversation

@mclasmeier
Copy link
Copy Markdown
Collaborator

Add explicit permissions blocks to workflows that were missing them (code-quality, unit-tests) and narrow the scope of release.yml by moving its contents: write from workflow level to job level.

GitHub Actions grants the GITHUB_TOKEN a default permission set that varies by repository visibility. For public repositories GitHub defaults to read-only, but this is a repository-level setting that an admin can change at any time. Explicit permissions blocks make the workflow self-documenting and immune to that drift:

  • If an admin later broadens the org or repo default, these workflows still only get the permissions they declare.

  • A compromised or malicious step in a job cannot escalate beyond the declared scope. For read-only workflows like linting and unit tests, this means a supply-chain attack on a third-party action cannot push code, create releases, or modify repository settings.

  • Moving release.yml's contents: write from workflow level to job level ensures that if new jobs are added to the workflow later, they don't silently inherit write access they don't need.

This follows the GitHub-recommended practice of always setting the minimum required permissions per job rather than relying on defaults.

Add explicit `permissions` blocks to workflows that were missing them
(code-quality, unit-tests) and narrow the scope of release.yml by
moving its `contents: write` from workflow level to job level.

GitHub Actions grants the GITHUB_TOKEN a default permission set that
varies by repository visibility. For public repositories GitHub
defaults to read-only, but this is a repository-level setting that an
admin can change at any time. Explicit permissions blocks make the
workflow self-documenting and immune to that drift:

- If an admin later broadens the org or repo default, these workflows
  still only get the permissions they declare.

- A compromised or malicious step in a job cannot escalate beyond the
  declared scope. For read-only workflows like linting and unit tests,
  this means a supply-chain attack on a third-party action cannot push
  code, create releases, or modify repository settings.

- Moving release.yml's `contents: write` from workflow level to job
  level ensures that if new jobs are added to the workflow later, they
  don't silently inherit write access they don't need.

This follows the GitHub-recommended practice of always setting the
minimum required permissions per job rather than relying on defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mclasmeier mclasmeier requested a review from vladbologa May 18, 2026 12:31
@mclasmeier mclasmeier merged commit 0879024 into main May 18, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants