Skip to content

Latest commit

 

History

History
241 lines (186 loc) · 12 KB

workflow-security.md

File metadata and controls

241 lines (186 loc) · 12 KB

Important Security Information for GitHub Actions

This guide aims to help contributors understand and author secure CI workflows. This guide is not complete, but provides many links to articles where you can learn more specifics about vulnerabilities and their mitigations.

Note: The details here are changing, especially with the recent supply-chain attacks that are taking advantage of insecure actions. Please open a pull request or Jira issue if this document needs updates.

Required Reading

  • Apache Infra. GitHub Actions Policy1. All changes MUST comply with this policy.

Suggested Reading

  • Understand GitHub Actions2 is a good high-level overview of GitHub Actions if you are not familiar or need a refresher.
  • Securing the open source supply chain across Github3.
  • Github Actions Secure Use Reference4

Security Conceptual Model

TL;DR: GitHub Actions are difficult to secure properly, especially for public repositories.

Since we allow the public to open pull requests against our repository, we are at risk of offering "remote code execution as a service". If we are not careful in how we build these workflows, attackers can:

  • Steal secrets granting write access to our repository.
  • Poison builds and/or container repositories with malicious code.
  • Execute arbitrary code on GitHub's infrastructure, which could be used to attack other repositories or services.

See Recent Supply Chain Attacks for real examples.

How Trigger Events Influence Security

These are some common events used to trigger workflows5 via the on: predicate. Understanding the behavior of these is critical to securing our workflows.

push

push events run a workflow when a commit or tag is pushed to the repository. push events run in the context of the branch that was pushed to. Although a push is typically performed by a trusted user (with write access), care is still required as these workflows can run with elevated permissions (i.e. default read + write GITHUB_TOKEN), making them vulnerable to things like variable injection attacks and secret exfiltration.

pull_request

By default6, a pull_request event runs a workflow when a pull request is opened, synchronized, or reopened. These workflows run in the context of the merge commit between the PR branch and the base branch. This means that if the PR is from a fork, the workflow will not have access to secrets and the GITHUB_TOKEN will have read-only permissions. This makes pull_request events generally safe to use for untrusted code, such as from forks.

According to GitHub's docs7:

Workflows don't run in forked repositories by default. You must enable GitHub Actions in the Actions tab of the forked repository.

With the exception of GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository. The GITHUB_TOKEN has read-only permissions in pull requests from forked repositories.

pull_request_target

privileged

The pull_request_target event runs when activity on a pull request (PR) in the workflow's repository occurs. By default8, the workflow runs when a pull request is opened, reopened, or when the head of the pull request branch is updated.

pull_request_target runs in the context of the default branch of the base repository, unlike pull_request, which runs in the context of the merge commit. While this feature originally aimed to prevent execution of unsafe code from the head of the pull request, it created a trap for many users who expected it to be a more secure version of pull_request. The elevated permissions for pull_request_target events (access to secrets and write permissions) opened new attack vectors.

If the workflow is configured to run on pull_request_target, it will have access to secrets and a GITHUB_TOKEN with write permissions, even for pull requests from forks. This means that if an attacker can find a way to trigger this workflow (e.g. by opening a pull request from a fork), they could potentially execute code with elevated permissions, which could lead to repository compromise or secret exfiltration.

Note that the behavior of this event recently changed: Prior to Dec. 2025, these events ran in the context of the PR's base branch, which could be used to target older versions of the codebase with vulnerabilities. Now it always uses the default base repo. branch.

From November 2026, ASF Infra disables pull_request_target for ASF repositories1. The PR "Build" check no longer uses it; see Build Checks for Fork Pull Requests. At the time of writing, labeler.yml and notify_cloud_aws.yml still use it and must be migrated separately.

workflow_run

privileged

workflow_run events are triggered when9 a workflow run is requested or completed. These events allow you to execute a workflow based on execution or completion of another workflow.

workflow_run events run in a privileged context: They can access secrets, and have write permissions, even if the previous workflow did not.

This is good and bad from a security perspective. These are useful in when you have a non-privileged workflow that you need to follow with a privileged one. This is Since they are privileged, though, you must be careful not to run untrusted code or depend on untrusted variables.

schedule and workflow_dispatch

privileged

schedule events run the workflow as merged on the default branch. workflow_dispatch events run it on any branch chosen by the user who dispatches it, including a branch that was never reviewed. Only users with write access can dispatch, so write access, not code review, is the trust boundary. Neither can be triggered by a pull request or from a fork. Both can hold secrets and a write token, so treat any data they read about pull requests or forks (titles, branch names, run results) as untrusted input.

Comparison

Trigger Context Secrets Access? GITHUB_TOKEN Permissions Risk Level
push The branch pushed to Yes Write (usually) Low (Only trusted users push)
pull_request The merge commit No (from forks) Read-only Low (Safe for untrusted code)
pull_request_target The base default branch Yes Write (usually) CRITICAL (Dangerous if misconfigured)
workflow_run The default branch Yes Write (usually) High (Runs after another workflow)
schedule The default branch Yes Write (usually) Low (Not triggered by PRs)
workflow_dispatch The branch chosen Yes Write (usually) Low (Only users with write access dispatch)

Build Checks for Fork Pull Requests

The upstream repository does not automatically build pull requests from forks. Instead, contributors enable GitHub Actions in their fork, where build_and_test.yml runs on push (or workflow_dispatch) with the fork's own token.

fork_ci_status.yml mirrors that run as the "Build" check on the upstream pull request, using ASF Infra's fork-ci action10. It replaced the earlier pull_request_target bridge (notify_test_workflow.yml and update_build_status.yml):

  • It runs only on schedule (every 10 minutes) and workflow_dispatch. It does not use the workflow_run signal that ASF policy recommends for this pattern: Zizmor flags that trigger as dangerous, and for builds that take hours, a check that appears on the next scheduled run is soon enough.
  • Its token has only actions: read, checks: write and pull-requests: read. It reads GitHub API metadata only, and never checks out, builds or downloads anything from the pull request or the fork.
  • The contributor controls the workflow that runs in their fork, so the "Build" check is informational. It does not replace code review or the Yetus precommit checks.
  • To mirror another fork workflow, add another fork-ci step with a distinct check name to fork_ci_status.yml. Keep all such steps in that one serialized workflow.

Contributor setup and rerun steps are in The "Build" Check on Pull Requests, which the check links to when it finds no run.

Recent Supply Chain Attacks

Here are a few of the more significant attacks recently exploiting insecure actions:

tj-actions/changed-files (March 2025): A massive attack affecting over 23,00011 repositories. Attackers compromised a personal access token (PAT) to update version tags with a malicious commit ([CVE-2025-30066]12) that dumped secrets into workflow logs.

reviewdog/action-setup (March 2025): Used as a "stepping stone"13 to compromise tj-actions, this incident (CVE-2025-3015414) highlighted how vulnerabilities in one action can cascade through the supply chain.

Trivy-action (March 2026): Attackers force-pushed version tags15 after compromising credentials with write access, exfiltrating secrets from every pipeline running a Trivy scan (CVE-2026-3363416). Setting aside the irony of a security scanning action becoming a vector for supply chain attacks, their final writeup17 contains good practices for mitigation.

Further Reading

We recommend learning more about specific attack techniques and their mitigations. This openssf.org blog post18 is a good overview, in addition to the rest of the links in this document.

References

Footnotes

  1. https://infra.apache.org/github-actions-policy.html ↩ ↩2

  2. https://docs.github.com/en/actions/get-started/understand-github-actions ↩

  3. https://github.blog/security/supply-chain-security/securing-the-open-source-supply-chain-across-github/ ↩

  4. https://docs.github.com/en/actions/reference/security/secure-use ↩

  5. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows ↩

  6. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request ↩

  7. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflows-in-forked-repositories ↩

  8. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target ↩

  9. https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_run ↩

  10. https://github.com/apache/infrastructure-actions/tree/fork-ci/v1.0.0/fork-ci ↩

  11. https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised ↩

  12. https://nvd.nist.gov/vuln/detail/CVE-2025-30066 ↩

  13. https://www.cisa.gov/news-events/alerts/2025/03/18/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction ↩

  14. https://www.cve.org/CVERecord?id=CVE-2025-30154 ↩

  15. https://github.com/aquasecurity/trivy/discussions/10425 ↩

  16. https://nvd.nist.gov/vuln/detail/CVE-2026-33634 ↩

  17. https://github.com/aquasecurity/trivy/discussions/10462 ↩

  18. https://openssf.org/blog/2024/08/12/mitigating-attack-vectors-in-github-workflows/ ↩