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 tokenSafer 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