Anchorflow

pull_request_target and workflow_run: running untrusted code safely

pull_request runs fork pull requests with a read-only token and no secrets. pull_request_target runs in the context of the base repository, with its secrets and a token that can write. That is useful for labelling or commenting, and dangerous if the job runs the contributor's code.

Where it goes wrong

The risky pattern is a pull_request_target (or workflow_run) job that checks out the pull request's head and then builds, installs or tests it. The contributor's build scripts then run with your secrets and a write token.

on: pull_request_target
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<sha>  # v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}   # untrusted code
      - run: npm ci && npm test                          # runs it with your token

Safer shapes

Run tests on pull_request, which has no secrets and a read-only token for forks. Keep pull_request_target for jobs that never check out or execute the pull request's code, such as labelling. If you must use the results of an untrusted build, split it: build on pull_request, upload an artifact, and handle it in a separate workflow that treats the artifact as data.

What Anchorflow checks

Anchorflow flags a pull_request_target or workflow_run job that holds a write token, and calls it out as critical when that job checks out untrusted pull request code. It does not run your workflow or follow reusable workflows across repositories.

Check your workflow