Skip to content

Pull Request vs Pull Request Target trigger

Today we’re looking at two very similar yet distinct event triggers: pull_request and pull_request_target. Understanding the differences between these triggers is crucial for the security of your CI/CD workflows. Let’s compare and contrast these triggers to help you choose the right one for your workflows.

The pull_request event trigger

The pull_request event trigger is activated whenever a pull request is created, synchronized, or updated in some way. This trigger is commonly used in workflows that require running tests, linters, or other checks on the code changes introduced by the pull request.

Key Features:

  • Context: runs in the context of the pull request branch. This means it has access to all the changes made in the pull request.
  • Security: since it runs in the context of the PR, it has limited access to secrets and other sensitive information stored in the base repository, providing a layer of security when running code from untrusted contributors.

Use case example: automatically running unit tests on the code changes submitted in a pull request.

on:
pull_request:
branches:
- main

The pull_request_target event trigger

Introduced to address specific security and workflow issues, the pull_request_target trigger behaves similarly to pull_request but with one crucial difference: it runs in the context of the base repository of the pull request, not the merge commit.

Key Features:

  • Context: runs in the context of the base branch (e.g., main), even if the workflow file is changed in the pull request.
  • Security: has full access to secrets and other sensitive information, making it suitable for workflows that need to deploy code, post results, or perform actions requiring elevated permissions.

Use Case Example: Posting a comment with the results of a CI test run on the pull request, requiring access to repository secrets for authentication with GitHub’s API.

on:
pull_request_target:
branches:
- main

Comparison and Considerations

  1. Security model:

    • pull_request: safer for public repositories or when accepting contributions from forks, as it restricts access to secrets.
    • pull_request_target: Ideal for workflows that need to interact with sensitive data or perform actions requiring full repository access.
  2. Access to code changes:

    • pull_request: has immediate access to the changes introduced in the pull request, making it straightforward for code checks.
    • pull_request_target: Requires extra steps (e.g., checking out the PR head manually) to access the changes in the pull request safely.
  3. Use cases:

    • Use pull_request for automated testing, linting, or any scenario where the workflow needs to run checks directly on the proposed changes without requiring access to protected resources.
    • Use pull_request_target for scenarios that require interacting with protected resources, such as deploying previews of changes or commenting on pull requests with sensitive information.

Best Practices

  • Be cautious with pull_request_target: given its access to sensitive information, ensure that workflows using pull_request_target do not blindly execute code from the pull request, which could expose your repository to security risks.
  • Prefer pull_request for code checks: for most automated code checks (like linting and testing), stick with pull_request to leverage its security model.
  • Securely handle code from forks: if you need to use pull_request_target to work with forks, consider adding safeguards, such as manual approval steps or additional validation, to mitigate potential security concerns.

Conclusion

Choosing between pull_request and pull_request_target depends on your specific workflow requirements and security considerations. Remember to review GitHub’s article on preventing pwn requests ↗ for further details and best practices.