Overly Permissive Workflow Permissions
GitHub Actions workflows with permissions: write-all or no explicit permissions block grant the GITHUB_TOKEN excessive access, allowing a compromised step to modify code, create releases, write packages, or change repository settings.
How It Works
Every GitHub Actions workflow run receives a GITHUB_TOKEN with permissions scoped to the repository. By default (for repositories created before February 2023), this token has read and write access to all repository scopes: contents, packages, issues, pull-requests, deployments, and more. If any step in the workflow is compromised (via a supply chain attack on an action, script injection, or dependency confusion), the attacker inherits all these permissions. They can push code to any branch, create releases with malicious artifacts, write to GitHub Packages, or modify issues and PRs. GitHub introduced fine-grained permissions to limit the GITHUB_TOKEN to only the scopes a workflow actually needs.
# BAD: no permissions block = default read-write to everything
name: CI
on: [push]
# No permissions block -- GITHUB_TOKEN gets full read-write access
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
---
# Also BAD: explicitly granting write-all
name: CI
on: [push]
permissions: write-all
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test # only needs read access, but has write-all# GOOD: minimal permissions at workflow and job level
name: CI
on: [push]
permissions:
contents: read # only what's needed at workflow level
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write # only this job needs deploy permission
steps:
- uses: actions/checkout@v4
- run: ./deploy.shReal-World Example
In 2022, the GitHub Actions team disclosed that workflows without explicit permissions blocks were a major risk surface. Several supply chain attacks exploited the default write-all GITHUB_TOKEN to push malicious code or publish tainted packages. GitHub changed the default for new repositories to read-only and introduced the permissions key specifically to address this attack vector.
How to Prevent It
- Set permissions: read-all or permissions: {} at the workflow level and grant specific permissions only to jobs that need them
- Change the default GITHUB_TOKEN permissions to read-only in your organization's Settings > Actions > General
- Use job-level permissions blocks to scope each job's GITHUB_TOKEN to the minimum required access
- Audit all workflow files for missing permissions blocks or overly broad permissions using actionlint or GitHub's security overview
Affected Technologies
Data Hogo detects this vulnerability automatically.
Scan Your Repo FreeRelated Vulnerabilities
Unpinned GitHub Actions
highUsing GitHub Actions referenced by mutable tags like @main or @v3 instead of full commit SHAs means a compromised or hijacked action can inject malicious code into your CI pipeline without any change to your workflow file.
GitHub Actions Script Injection
criticalUsing untrusted event data like github.event.issue.title directly inside run: blocks allows attackers to inject arbitrary shell commands into your CI pipeline by crafting malicious issue titles, PR bodies, or commit messages.
Secrets Leaked in CI Logs
highPrinting or echoing environment variables containing secrets in CI scripts exposes them in build logs, which are often accessible to all repository collaborators and sometimes publicly visible on open-source projects.
Self-Hosted Runner Risks
highUsing self-hosted GitHub Actions runners with pull_request_target or public fork workflows allows untrusted code from external contributors to execute on your infrastructure with access to secrets, persisted state, and the host network.