GitHub Actions

GitHub Actions GITHUB_TOKEN permissions: least privilege

Declare GITHUB_TOKEN permissions explicitly at the workflow top level, grant write scopes only on the jobs that need them, and verify repository and organization workflow-permission settings before debugging blocked pull-request automation.

Key takeaways for GITHUB_TOKEN permissions

  • GitHub says an action can access GITHUB_TOKEN through the github.token context even when the workflow does not explicitly pass the token to the action. [1]
  • GitHub recommends limiting GITHUB_TOKEN to the minimum access required by the workflow or job. [1]
  • GitHub documents permissions as the workflow key for setting GITHUB_TOKEN access, including read-all, write-all, {}, and per-scope read, write, or none. [2]
  • GitHub documents that once any permission is specified, unspecified permissions are set to none. [2]
  • OpenSSF Scorecard's Token-Permissions check rewards workflows that declare read-only permissions at the top level and put required write permissions at the job level. [4]
  • New personal repositories and new organizations default GITHUB_TOKEN to read-only contents and packages scopes and block pull-request creation until Allow GitHub Actions to create and approve pull requests is enabled under Settings > Actions > General. [5] [6]

Make least privilege visible in the YAML

Bottom line: Start workflows with permissions: read-all or the narrower contents: read, then grant specific write scopes only on the jobs that create issues, publish packages, request OIDC tokens, update statuses, or change repository state.

GitHub's authentication guide says workflows can use GITHUB_TOKEN for actions, GitHub CLI calls, and API requests. It also says actions can access the token through the github.token context even if the workflow does not explicitly pass it. [1] That is why token permissions deserve review even in workflows that do not show secrets.GITHUB_TOKEN in a step.

The practical control is the permissions key. GitHub says this key can be used for an entire workflow or for individual jobs, and that it lets maintainers configure the minimum required permissions. [1]

Default token access is too implicit for review

GitHub's workflow syntax reference lists permissions under the top-level workflow syntax and under jobs.<job_id>.permissions. [2] It also documents broad shortcuts, including read-all, write-all, and {}. [2]

Those shortcuts are useful when they make intent obvious. permissions: read-all tells reviewers the workflow starts read-only. permissions: {} tells reviewers the workflow starts with no token permissions. permissions: write-all usually deserves extra scrutiny because it hides which write capability the job truly needs.

Reviewable baseline: A top-level read-only baseline plus job-level write exceptions makes privilege easier to scan than a workflow that relies on repository defaults.

Align repository and organization workflow-permission settings

YAML permissions blocks work alongside repository and organization controls under Settings > Actions > General > Workflow permissions. GitHub Docs describes two default presets on that screen: a permissive preset granting GITHUB_TOKEN read and write scopes broadly, and a restricted preset limiting the token to read-only contents and packages access. [5] [6]

Newly created personal-account repositories and newly created organizations both start on that restricted contents and packages read-only preset. [5] [6] New repositories inside an organization inherit the organization's configured baseline instead. [5] When an organization enforces the restricted preset, member repositories inherit that selection with the permissive radio button disabled; similarly, a restrictive GitHub Enterprise policy prevents organization admins from picking the permissive option. [5] [6]

Even under a restricted UI preset, contributors who hold repository write access can still grant or narrow job and workflow GITHUB_TOKEN scopes through the workflow file's permissions key. [5] [6] Pull-request creation uses a separate checkbox: new personal repositories and new organizations block workflows from opening or approving pull requests by default. [5] [6]

Fixing blocked pull-request creation: When a release or automation job needs GITHUB_TOKEN to open or approve a pull request, declare job-level pull-requests: write in YAML [2] and confirm that "Allow GitHub Actions to create and approve pull requests" is checked under Settings > Actions > General > Workflow permissions (or at the organization level when inherited policy disables the repository checkbox). [5] [6]

A top-level baseline keeps accidental write scope out

GitHub documents that if a workflow specifies access for any permission, all permissions not specified are set to none. [2] That behavior lets teams use a short baseline instead of repeating every permission name.

  • Read-only baseline: use permissions: read-all when most jobs only need to read repository contents and metadata.
  • Narrow baseline: use permissions: contents: read when the workflow only needs repository content reads.
  • No-token baseline: use permissions: {} when jobs should not receive repository token access unless a job explicitly opts in.

OpenSSF Scorecard mirrors that posture in its Token-Permissions remediation guidance: set top-level permissions as read-all or contents: read, then set required write permissions at the job level. [4]

Write scopes belong beside the step that needs them

GitHub's token guide uses job-level permissions examples for creating an issue with the GitHub CLI and with the REST API. [1] That pattern is useful because the permission sits near the behavior it enables.

A release job that publishes a package may need a package write scope. An issue triage job may need issue write scope. A cloud deployment using OpenID Connect may need id-token: write [2]; GitHub's secure-use reference recommends considering OIDC for deployments that need short-lived, well-scoped cloud tokens. [3]

Caution: A job that only checks out code, runs tests, or reads metadata should not inherit write scopes just because a later release or comment job needs them.

Pull-request workflows need token review before merge

Token scope interacts with workflow triggers. GitHub's workflow syntax reference notes special permission behavior for pull_request_target, and the CI Tripwire guide on pull_request_target security explains why privileged pull-request automation should stay away from untrusted pull-request code. [2]

For ordinary pull-request CI, a read-only or no-token baseline reduces the impact of unexpected token access. For privileged pull-request metadata work, the workflow should show exactly why a write scope exists and should avoid running code from the pull request.

A first audit can start with five searches

Search workflow YAML for permissions:, write-all, secrets.GITHUB_TOKEN, github.token, and pull_request_target. Those strings map to the source-backed review areas in this guide: explicit token scope, broad write grants, implicit token access, and privileged pull-request automation. [1] [2]

For a local review queue, run gha-guard against the repository and inspect any token-permissions, trigger, checkout, timeout, or shell-context findings before merging workflow changes.

CI Tripwire Editorial has not commissioned independent expert review of this article. Read more about the organization byline at contributors and the source posture at sourcing.

Corrections can be routed through the corrections note. Sources: 6 entries, primary platform, security reference, and project documentation, last reviewed 2026-10-26.

Sources

  1. GitHub Docs, Use GITHUB_TOKEN for authentication in workflows.
  2. GitHub Docs, Workflow syntax for GitHub Actions.
  3. GitHub Docs, Secure use reference.
  4. OpenSSF Scorecard, checks documentation: Token-Permissions.
  5. GitHub Docs, Managing GitHub Actions settings for a repository, retrieved 2026-10-26.
  6. GitHub Docs, Disabling or limiting GitHub Actions for your organization, retrieved 2026-10-26.