Search code examples
github-actionspull-request

What is the difference between pull_request and pull_request_target event in GitHubActions


What is the difference between pull_request and pull_request_target event in GitHubActions?

I found this explanation in the GitHubActions Docs:

This event (pull_request_target) runs in the context of the base of the pull request, rather than in the context of the merge commit, as the pull_request event does.

But, I can't understand what the context in githubAction is. Can anybody explain it?


Solution

  • That is summarized in "Github Actions and the threat of malicious pull requests" by Nathan Davison:

    When Github first launched Actions in 2018, this was not the case (or at least, it wasn't intended to be) - in Actions terminology, the pull_request event and its variants were the only events that triggered on a PR being opened from a fork, and these events were made to not have access to repo secrets, including having access to a GITHUB_TOKEN value that is read-only.

    However, sometime later, in August 2020, the pull_request_target event was added.

    This event is given repo secrets and a full read/write GITHUB_TOKEN to boot, however there is a catch - this action only runs in the pull request's target branch, and not the pull request's branch itself.

    This differs from the CircleCI approach, which happily checked out the pull request's code when it was instructed to share secrets with PRs from forked repositories, including the pipeline configuration in the pull request (that would allow pull requests to be submitted just to steal tokens and secrets stored within the settings of a CircleCI project).

    The blog post confirms:

    In order to protect public repositories for malicious users we run all pull request workflows raised from repository forks with a read-only token and no access to secrets.
    This makes common workflows like labeling or commenting on pull requests very difficult.

    In order to solve this, we’ve added a new pull_request_target event, which behaves in an almost identical way to the pull_request event with the same set of filters and payload.

    However, instead of running against the workflow and code from the merge commit, the event runs against the workflow and code from the base of the pull request.

    This means the workflow is running from a trusted source and is given access to a read/write token as well as secrets enabling the maintainer to safely comment on or label a pull request.
    This event can be used in combination with the private repository settings as well.


    Is pull_request_target safe to use?

    The pull_request_target event grants workflows triggered by pull requests from forks access to repository secrets and a read/write GITHUB_TOKEN. That is inherently risky if the workflow inadvertently exposes these secrets or allows for unauthorized modifications to the repository.

    Another risk: the workflow attempts to check out and execute code from the pull request. Since this event runs in the context of the target branch with access to secrets, executing code from the PR without strict controls can expose secrets to untrusted code.

    So it is best to:

    • only use pull_request_target for workflows where access to secrets or write permissions is strictly necessary, such as commenting, labeling, or status updates on pull requests.
    • have mechanisms in place to review or sandbox the code before execution if you must use pull_request_target and need to interact with the code from the pull request: only run certain actions after manual approval via pull request reviews.
    • implement conditional logic within your workflows to make sure steps requiring secrets or write permissions are only executed under safe conditions.
    • explicitly specify the commit or branch you trust instead of checking out the PR's head commit blindly, when your workflow requires checking out code.

    Other best practices: "Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests" by Jaroslav Lobačevski.