How to Avoid Running Untrusted Code With pull_request_target
pull_request_target runs in the base repo context with secrets and write access, so executing fork code there is a full compromise.
Use pull_request (read-only, no secrets) for anything that runs contributor code. Reserve pull_request_target for trusted metadata tasks that never check out or run the fork.
Steps
- Use
pull_requestfor build and test of contributor changes. - In
pull_request_target, nevercheckoutthe PR head ref and run it. - Keep secret-bearing jobs off any workflow that executes fork code.
Safe metadata-only pull_request_target
.github/workflows/labeler.yml
on: pull_request_target
permissions:
pull-requests: write
jobs:
label:
runs-on: ubuntu-latest # not self-hosted
steps:
# No checkout of PR code, no build, no run of fork scripts
- uses: actions/labeler@v5Gotchas
- Checking out
github.event.pull_request.head.shaunder pull_request_target runs attacker code with secrets. - Even a "safe" build script from a fork can contain a malicious postinstall hook.
Related guides
How to Avoid Self-Hosted Runners on Public RepositoriesKeep self-hosted GitHub Actions runners off public repositories, where a forked pull request can run attacker…
How to Pin GitHub Actions by Commit SHAProtect self-hosted runners from supply-chain attacks by pinning third-party GitHub Actions to a full commit…