Safeguard
Developer Tools•

What GITHUB_TOKEN permissions should security automation have?

Set the permissions key on every automation workflow and grant only what each job writes. A permission map for ticket, label, comment and report jobs.

Safeguard Security Team
3 min read

Give each automation job only the permissions it writes with. Set the permissions key explicitly, start from read access to contents, and add one write scope per job, such as issues write for ticket creation. Anything broader turns a small script bug into a repository incident.

Why this matters for automation

Security automation runs unattended, handles untrusted text such as pull request titles and advisory descriptions, and often has write access. That combination is where mistakes become incidents. GitHub's documentation says that actions can reach the token through the github.token context even when you do not pass it in, and recommends that you always limit the token to the minimum access needed.

The permissions key can be set for a whole workflow or for individual jobs. GitHub's tutorial examples set it at job level: one job has contents: read and issues: write, another only issues: write. If you need access the GITHUB_TOKEN cannot offer, the docs point to a GitHub App installation token, or alternatively a personal access token stored as a secret.

A permission map

Automation jobTypical permissions
Create tickets as GitHub issuesissues: write
Label pull requests by pathpull-requests: write, contents: read
Comment scan results on a pull requestpull-requests: write
Upload code scanning resultssecurity-events: write
Scheduled report to chatcontents: read only
Read advisories and open a fix branchcontents: write, pull-requests: write

Check the exact scope names in GitHub's workflow syntax reference for your case, because they change as features are added. Our rule of thumb: if a job posts to an outside service such as chat or Jira, it often needs only contents: read on the GitHub side, since its write access lives in a separate secret.

Steps to tighten an existing workflow

  1. List every job and what it changes.
  2. Add a top-level permissions: {} or contents: read to set a low default.
  3. Add job level permissions only where a write is needed.
  4. Run the workflow and read the failures. A 403 tells you which scope is missing.
  5. Re-run, and record the final map in the repository's docs.

Secrets travel with permissions

Every secret a job can read is an extra permission. GitHub documents environment secrets that are only released to jobs that pass the environment's rules. Keep chat webhook URLs and ticketing tokens in a narrower scope than your deploy keys, and do not expose them to jobs that run on pull requests from forks. For related reading see one connection per automation and personal login or service account.

Review the map regularly

Permissions creep. Someone adds write-all to get a build green, and it stays. Put workflow files under code owners review and grep for broad grants as part of a quarterly check. Our guardrails checklist for security automation includes the full list.

Quick check

Is the default token read only?

That depends on your repository and organization settings, so do not assume. Set the permissions key explicitly in each workflow.

When do I need a GitHub App instead?

When the job needs access the GITHUB_TOKEN cannot provide, or needs to trigger further workflow runs.

Sources

Safeguard offers agent identity and policy features for governing what automated agents are allowed to do. Try the free scan at gold.safeguard.sh/scan.

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.