Secure the pipeline

Minimize token permissions

Give GITHUBTOKEN no more repository access than each workflow or job requires.

Every workflow receives a GITHUB_TOKEN. It is temporary, but it is still a credential. Broad write access turns a script injection or compromised action into a repository takeover.

The default permissions for new repositories changed over time. Older repos may still grant contents: write to every workflow. Check repository settings under Actions > General and align the default with your least-privilege YAML.

My default: start with almost no permission, then add back only what breaks.

Set restrictive defaults at the top

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

Pull request tests usually need read access to code, nothing else.

Grant write only where needed

Publishing releases or commenting on pull requests needs explicit scope on that job:

  release:
    needs: test
    permissions:
      contents: write
      id-token: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./scripts/create-release.sh

Other jobs never see contents: write.

Prove it by breaking on purpose

Set permissions: {} or contents: read only. Run the workflow. When a step fails with “Resource not accessible by integration”, read the docs for that action and add the smallest permission that fixes it.

Do not copy permissions: write-all from an old template because the token expires at the end of the job. An attacker does not need long-lived access. One write call to main is enough.

Some actions need pull-requests: write to comment or packages: write to publish. Grant those on the job that calls the action, not on the whole workflow.

Document required permissions in the runbook next to each job name. Future you will forget why id-token: write exists.

Try this on your own project: list every job and the minimum permission it needs. Compare that list to your current YAML.

Lesson completed