Why is this an issue?

Using permissions: read-all or permissions: write-all grants all read or write permissions to a job, violating the principle of least privilege. Jobs should only have the specific permissions they need.

For example, a job that only needs to read issues should not have access to read code, pull requests, or packages. A job that only needs to write files should not be able to create releases, modify deployments, or write to other repositories.

What is the potential impact?

If a workflow or job is compromised (e.g., via malicious code injection, supply chain attack, or accidental exposure), excessive permissions can lead to:

Data Exposure

If a workflow or job with read-all permission is compromised, an attacker can access sensitive data in issues, pull requests, or packages etc.

Unauthorized Modification

If a workflow or job with write-all permission is compromised, an attacker can create or modify issues, pull requests, releases, or deployments etc.

Supply chain compromise

If a workflow or job with write-all permission is compromised, an attacker can publish malicious packages or modify artifacts

How to fix it

Replace read-all and write-all with specific permissions that match the job’s actual needs. If a job needs multiple permissions, list them explicitly:

permissions:
  contents: read
  pull-requests: read
  issues: write

Code examples

Noncompliant code example

name: Example
jobs:
  test-job:
    permissions: read-all # Noncompliant
    runs-on: ubuntu-latest
    steps:
      # Do something that requires 'contents: read' permissions.
name: Example
permissions: write-all # Noncompliant
jobs:
  example:
    runs-on: ubuntu-latest
    steps:
      - name: hello
         # Do something that requires 'contents: write' permissions.

Compliant solution

name: Example
jobs:
  test-job:
    permissions:
      contents: read
    runs-on: ubuntu-latest
    steps:
      # Do something that requires 'contents: read' permissions.
name: Example
jobs:
  example:
    permissions:
      contents: write
    runs-on: ubuntu-latest
    steps:
      - name: hello
         # Do something that requires 'contents: write' permissions.

How does this work?

GitHub Actions enforces permissions through the GITHUB_TOKEN automatically provided to each workflow run. When you specify permissions in a workflow, GitHub restricts the token’s scopes for that job.

When a job uses permissions: read-all, GitHub grants all read permissions to the GITHUB_TOKEN for that job. Similarly, permissions: write-all grants all write permissions. This means any step in the job can perform any read or write operation, even if it’s not needed.

By specifying individual permissions like permissions: contents: read, GitHub restricts the token to only that scope. If a step tries to access other resources (e.g., reading issues with only contents: read), GitHub returns 403 Forbidden, preventing unauthorized access.

Resources

Documentation

Standards