Missing Permissions Block
Description
When a workflow does not declare a permissions block — and not every job sets its own — the GITHUB_TOKEN falls back to the repository or organization default permissions. Depending on repository settings, that default can be the permissive read/write token, granting the workflow far more access than it needs. 1 Declaring an explicit, least-privilege permissions block at the workflow level (and widening it per job only where required) shrinks the attack surface if the workflow is ever compromised through a malicious dependency, action, or injected command. Related permission findings include Overly Permissive and Excessive Write Permissions.
Vulnerable Instance
- The workflow has no top-level
permissionskey. - At least one job also omits a job-level
permissionskey, so itsGITHUB_TOKENuses the repository default.
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
# No permissions declared anywhere — GITHUB_TOKEN uses the repo default,
# which may include write access to contents, packages, deployments, etc.
steps:
- uses: actions/checkout@v4
- run: make testMitigation Strategies
Set a least-privilege default at the workflow level Start from read-only and grant only what is required.
permissions: contents: readWiden per job, not globally If a single job needs to write (for example, to publish a release or push a comment), grant that scope on the job rather than the whole workflow.
jobs: release: permissions: contents: writeSet the organization/repository default to read-only Configure the default
GITHUB_TOKENpermissions to read-only so workflows must opt in to write access explicitly.Review token scopes regularly Audit workflows to confirm each declared permission is still required.
Secure Version
name: CI
on: [push]
+permissions:
+ contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make test
Impact
| Dimension | Severity | Notes |
|---|---|---|
| Likelihood | Many workflows omit an explicit permissions block and silently inherit the repository default. | |
| Risk | Not directly exploitable on its own, but it removes a key mitigation: a compromised step inherits broader token access than necessary. | |
| Blast radius | Depends on the repository default; a write-capable token reachable by a compromised step can modify repository contents and other resources. |
References
- GitHub Docs, “Assigning permissions to jobs,” https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs 1
- GitHub Docs, “Security hardening for GitHub Actions — Using the GITHUB_TOKEN,” https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-the-github_token-in-a-workflow 2
GitHub Docs, “Assigning permissions to jobs,” https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs ↩︎ ↩︎
GitHub Docs, “Security hardening for GitHub Actions,” https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-the-github_token-in-a-workflow ↩︎