Use pull_request for anything that builds or tests code from a fork, because it runs without secrets and with a read-only token. Use pull_request_target only for light tasks like labeling, and never check out and run the fork's code inside it.
What pull_request does
For a pull request from a fork, the event goes to the base repository. GitHub's documentation says secrets are not passed to the runner, except the GITHUB_TOKEN, and the token has read-only permissions in pull requests from forked repositories.
Workflows also do not run in forks by default, and for public repositories a maintainer may need to approve runs from first time contributors. Dependabot pull requests follow the same fork restrictions.
That makes it the right default for tests, linters and builds.
What pull_request_target does
This event runs in the context of the base repository's default branch, not the merge commit. It is designed for tasks like labeling or commenting on fork pull requests. The documentation advises avoiding it if you need to build or run pull request code.
The docs warn that running untrusted code on this trigger can cause vulnerabilities, including cache poisoning and unintended write access to secrets or privileges. The secure use page adds that these triggers, when combined with a checkout of an untrusted pull request, expose the repository to compromise.
The pattern to avoid
The dangerous combination is two steps:
on: pull_request_target
jobs:
test:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: npm install && npm test
The trigger gives the job a privileged context. The checkout brings in attacker controlled files. The install step then runs attacker controlled scripts with those privileges.
Safer designs
If you need to test fork code and then do something privileged, split the work.
- Run the untrusted build under
pull_request, with no secrets. - Upload the result as an artifact.
- Use a second workflow on
workflow_runto do the privileged step.
GitHub recommends workflow_run for separating privileges, and also says to treat artifacts from the earlier workflow with caution. The artifact is untrusted input. Read it as data, never execute it. See separating privileges with workflow_run.
Review checklist
- Does any workflow use
pull_request_target? Why? - Does it check out a ref from the pull request?
- Does it run scripts, install packages or invoke tools from that checkout?
- Does the job have write permissions or secrets it does not need?
- Is the workflow file protected by CODEOWNERS?
If the answer to the second and third question is yes, redesign it.
Safeguard policies and gates can hold merges that fail checks, and the free scan at gold.safeguard.sh/scan is a starting point for reviewing a repository.
Quick check
Is pull_request_target ever fine?
Yes, for tasks that never run code from the pull request, such as adding a label or posting a comment.
Does read-only GITHUB_TOKEN make pull_request_target safe?
Not by itself. The docs do not state the token or secret behavior for this event, so set permissions explicitly and avoid running fork code.
Sources
Last reviewed: 19 October 2026.