GitHub Actions vulnerability-alerts Permission: Read Dependabot Alerts Safely

Use GitHub Actions to read Dependabot alerts with the narrow vulnerability-alerts permission, understand what it covers, and avoid granting broader token access.

A narrow glowing channel carries one dependency alert from a shielded vault into a workflow while unused keys remain locked

GitHub Actions can now read Dependabot alerts with a permission made for that one job: vulnerability-alerts: read. It is a small addition, but it closes a common least-privilege gap. A workflow that reports vulnerable dependencies no longer needs a broad token permission just to inspect alert data.

This post shows the smallest useful workflow, explains what the permission does not cover, and collects the practical details that matter when a request returns 403. The feature was announced in GitHub's September 2026 Actions update.

The new permission in one minute

The permissions map now includes vulnerability-alerts. GitHub supports read and none for it. write is not a valid value. read allows a workflow's GITHUB_TOKEN to retrieve Dependabot alert data for the repository where the workflow is running. none removes that access.

The current workflow syntax reference lists the permission as the one used to read Dependabot alerts. It is separate from security-events, which is used for code scanning results, and it does not grant access to secret scanning alerts.

name: Dependabot alert summary

on:
  workflow_dispatch:

permissions:
  vulnerability-alerts: read

jobs:
  alerts:
    runs-on: ubuntu-latest
    steps:
      - name: List open alerts
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh api repos/${{ github.repository }}/dependabot/alerts \
            --paginate \
            --jq '.[] | select(.state == "open") | [.dependency.package.name, .security_advisory.severity, .html_url] | @tsv'

This example only lists open alerts. It does not check out the repository, so it does not need contents: read. The token is passed to gh through GH_TOKEN, which is the supported way for GitHub CLI commands to authenticate inside Actions.

Why the permissions block matters

Once a workflow declares any permissions, every permission you do not name becomes none. That behavior is useful: it makes the token's access visible and prevents a future default from silently adding more authority. It also means a workflow that checks out code needs to opt into contents: read explicitly.

permissions:
  contents: read
  vulnerability-alerts: read

Keep permissions at the workflow level when every job needs the same access. Put them on one job when only the reporting job needs alert data. Job-level permissions make the boundary easier to audit in a larger workflow.

name: Build and security report

on:
  pull_request:

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

  report:
    permissions:
      vulnerability-alerts: read
    runs-on: ubuntu-latest
    steps:
      - env:
          GH_TOKEN: ${{ github.token }}
        run: gh api repos/${{ github.repository }}/dependabot/alerts --paginate

Read does not mean remediate

The new permission is for inspection. It is a good fit for a daily summary, a pull request comment, a dashboard feed, or a policy check that fails when an open alert crosses a severity threshold. It is not an alert-management permission, and there is no vulnerability-alerts: write value to add.

If a workflow must dismiss or reopen alerts, treat that as a different trust boundary. Use a GitHub App or a fine-grained personal access token with the exact repository permission required by the API operation. Do not turn a routine read-only report into a privileged remediation job.

The Dependabot alerts REST API documentation lists the repository endpoint and its current authentication requirements. GitHub marks this API as public preview, so check the current reference before building a long-lived integration.

Three useful patterns

  1. Scheduled inventory: run once or twice per day, collect open alerts, and publish a small report. Keep the job read-only and make the output easy to compare with the previous run.
  2. Pull request guardrail: query alerts when a change touches dependency files, then warn or fail according to your policy. Keep the policy decision in the workflow, but link back to the alert URL so the fix has a clear owner.
  3. Repository dashboard: fetch alert counts and severity data for the current repository, then send only the summary to your monitoring system. The endpoint is repository-scoped, so an organization-wide view needs an explicit loop over repositories and its own rate-limit plan.

Troubleshooting a 403

Check these in order:

  1. The workflow has vulnerability-alerts: read at the level where the API call runs.
  2. Dependabot alerts are enabled for the repository and the endpoint is being called for the current repository.
  3. The job is not relying on an unrelated permission such as security-events or contents. Those permissions do not substitute for vulnerability-alerts.

For pull_request workflows from forks, remember that GitHub applies read-only token rules and does not pass ordinary repository secrets to the runner. That is a useful safety property, but it means a workflow that depends on secrets or write access needs a separate design.

Security checklist

  • Declare the narrow permission instead of using read-all.
  • Set permissions per job when only one job needs alert data.
  • Pass the token through GH_TOKEN and never print it.
  • Keep alert reading separate from jobs that modify code, releases, or repository settings.

For a read-only Dependabot report, vulnerability-alerts: read is the permission to reach for. It gives the workflow a clear, narrow capability and keeps the rest of the token surface closed. Start there, add only the permissions a later step genuinely needs, and keep remediation credentials out of routine reporting jobs.