Writing GitHub Actions securely is notoriously difficult. While the default behavior is relatively secure, certain features may have non-obvious security implications.

The Apache Infrastructure GitHub Actions Policy has the formal rules around the use of GitHub actions. The content below is intended to be more practical advice.

Threat model

We're trying to protect:

We mainly focus on attacks that can be triggered by external attackers, though ideally compromised committer accounts should also be considered.

Workflow approval

By default, ASF repositories require approval before building PRs by non-committers.This has some limitations:

Default GITHUB_TOKEN permissions

Each build will have access to a GITHUB_TOKEN to perform GitHub API calls. The permissions associated with this token depend on the trigger that started the build. You can find an overview here. Tokens for workflows triggered by pull_request are safe, but others are not. For those:

Builds triggered with pull_request_target 

Builds triggered by the pull_request_target event (as opposed to pull_request) by default check out the 'target' branch of the PR, and run with a 'permissive' GITHUB_TOKEN. It is common for such workflows to switch to the PR that triggered the workflow. This is dangerous, as any code that is loaded from the repo and run after the switch (including actions, scripts, build tools and test code) may be untrusted, and will have access to the GITHUB_TOKEN.

Builds triggered with issue_comment 

Similarly, builds triggered with issue_comment  run with a 'permissive' GITHUB_TOKEN. Again, no code may be loaded after switching to the PR branch. You use this technique to switch to the branch.

Builds triggered with workflow_run

A common technique for building untrusted code but also using privileges to act on the build result is to split the build into two parts: a low-privilege one triggered by pull_request that runs the untrusted code, stores the result in an artifact, and triggers a second, high-privilege build with workflow_run  that acts on that result.

In such a scenario, you must be careful to make sure all evaluation of untrusted code happens in the pull_request  build, and no untrusted code is executed in the workflow_run part of the workflow.

When extracting and using the artifacts it is important to remember that they were produced in an untrusted context and their content is not to be trusted:


3rd-party actions

The Apache Infrastructure GitHub Actions Policy states actions outside of apache/*, github/* and actions/* must be pinned to the specific git hash (SHA1) of the action that has been reviewed for use by the project. For instance, you MUST pin foobar/baz-action@8843d7f92416211de9ebb963ff4ce28125932878.

Fixing workflows

When a security issue is fixed in a workflow triggered by pull_request_target, you must not only fix it on your main branch, but fix/delete all branches that have the vulnerable workflow, as PRs to those branches would still trigger the vulnerable code.

Further mitigations