Workflow protections GA: keep the Sume key off fork PR runs

GitHub's workflow execution protections are GA. Pair them with a Sume workflow that only runs on push, schedule or dispatch, so a fork PR never sees the key.

5 min readSume
All posts

Should a pull request from a fork ever be able to spend your Sume credits? No. The simplest rule is that the job holding SUME_API_KEY never runs for a pull request at all. GitHub's workflow execution protections, which went generally available on September 17, give you a policy layer that enforces rules of this kind across a repository or organization (read 2026-10-04). This post shows the workflow shape that makes the rule true on its own, and where the new protections add a second lock.

Sume's authentication docs are blunt about why this matters: an API key's scopes are fixed when you create it, and a key that shows up in logs, screenshots or tickets should be rotated. A leaked key on a paid API is a billing problem, not just a security one.

What the GA release adds

According to the changelog, workflow execution protections let admins set rules by actor and by event, and the general availability release adds targeting by workflow file, insights, a REST API, and an evaluate mode for trying a rule before it blocks anything (read 2026-10-04). It also describes a default protection against the pull_request_target event in public repositories.

That last item is the one that touches paid APIs most. pull_request_target runs in the context of the base repository, which is where secrets live, while the code under test can come from a fork. A workflow that calls a paid API from that trigger is the classic way a key gets read by someone else's code.

Workflow execution protections, as described by GitHub (read 2026-10-04)
CapabilityWhy it matters for a Sume key
Rules by actorLimit who can start a workflow that has the secret
Rules by eventBlock the events that carry fork code into a secret-bearing job
Workflow-file targetingApply a rule only to the file that calls Sume
Evaluate modeSee what a rule would have blocked before enforcing it
REST API and insightsAudit the policy instead of trusting a settings page

A workflow that never needs the policy to save it

Policy is a backstop. The workflow itself should only listen to events where the code is yours. Below, the Sume job runs on a push to main, on a weekly schedule, and on manual dispatch. There is no pull_request or pull_request_target trigger, so there is no fork path to the secret to begin with.

The step submits nothing paid. It reads GET /v1/balance and fails the job when the available balance is below a floor you choose, which is a useful gate before a batch step runs. Sume documents /v1/balance as a free read. Only one credential header is sent, because sending both Authorization and x-api-key returns 401 unauthorized.

name: sume-balance-gate
on:
  push:
    branches: [main]
  schedule:
    - cron: '5 7 * * 1'
  workflow_dispatch:
permissions:
  contents: read
jobs:
  balance:
    runs-on: ubuntu-latest
    steps:
      - name: Check balance
        env:
          SUME_API_KEY: ${{ secrets.SUME_API_KEY }}
        run: |
          set -eu
          code=$(curl -sS -o /dev/null -w '%{http_code}' \
            https://api.sume.com/v1/balance \
            -H "x-api-key: $SUME_API_KEY")
          echo "GET /v1/balance -> $code"
          test "$code" = 200

Where cache-mode fits

A second GitHub change from September 10 is relevant in a different way. The cache-mode setting controls whether a job can read from, write to, both, or neither of the Actions cache, with values read, write, write-only and none, and a job-level setting overrides a workflow-level one. Per the changelog, untrusted events default to read (read 2026-10-04).

If your Sume workflow caches downloaded tools, that default means a fork-triggered run cannot poison the cache your keyed job later restores. This post does not show cache-mode YAML, because the changelog entry describes the values without giving the exact syntax; take that from GitHub's documentation. The point for Sume users is conceptual: a cache is a shared surface, and the job that holds a paid key should only restore from caches written by trusted events.

A short review list

Run through this once per repository that calls Sume. Each item is a check you can finish in a few minutes, and the evaluate mode in the new protections is a safe way to confirm the policy side without blocking anyone.

When a key is found somewhere it should not be, rotate it and review recent usage with GET /v1/usage, which Sume documents as a free read. For retries after a runner failure, see the post on idempotency keys for re-run workflows.

  • Search workflow files for pull_request_target and for any pull_request job that references the secret.
  • Keep the Sume key in a repository or environment secret, never in a workflow file or an artifact.
  • Give the job permissions: contents: read unless it needs more.
  • Prefer a key created only for CI, so rotating it affects nothing else.
  • Turn on evaluate mode for a new event rule first and read what it would have blocked.

Sources

Related posts

More in Integrations

All Integrations posts

Written by Sume