DUE TO SPAM, SIGN-UP IS DISABLED. Goto Selfserve wiki signup and request an account.
...
We mainly focus on attacks that can be triggered by external attackers, though ideally compromised committer accounts should also be considered.
Helpful tools
There are some validation tools that can help you identify risky patterns in your actions:
- Zizmor can be ran standalone or as a workflow
- CodeQL "Actions" scanning
- The ASF Infra team has a scanner for flagging obvious policy violations
- The ASF Tooling team is working on a scanner, though results are not public yet.
Workflow approval
By default, ASF repositories require approval before building PRs by non-committers.This has some limitations:
- This restriction does not apply to workflows triggered by
pull_request_targetorissue_comment - This restriction does not protect against compromised committer accounts
- When using the 'checkout' action to check out the relevant PR, do not specify the
refas "refs/pull/${{ github.event.number }}/merge" or "github.event.pull_request.head.ref": the PR may have been updated since the workflow was approved. Instead, leave therefempty to use the code associated with the event that triggered the build (which should what it looked like when it was approved), or use the exact commit hash.
Action allowlisting
The ASF GitHub org only allows action versions that have been added to the org-wide allowlist. You're invited to add actions you'd like to use to this allowlist, and review new versions as they appear.
Default GITHUB_TOKEN permissions
...
If you think you cannot avoid dangerous workflows - it's best if you reach out to #builds slack channel on ASF slack - there is a group of peple there who discuss various ways you can design your Github Actions in the way to avoid dangerous workflows.
It's highly recommended to use There are some typical tasks done wit pull_request_target - for example labeling PRs with https://woodruffw.github.io/zizmor/ static analysis tool in your CI / pipelines to detect and fix potential security issues in your workflowsgithub.com/actions/labeler. Those could be often replaced with GitHub Apps - for example there is a "Boring Cyborg" GitHub App: https://github.com/kaxil/boring-cyborg that has similar functionality (among others). Also Boring Cyborg could be extended if some functionalities are missing. PRs are most welcome.
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 As long as only code from the trusted/reviewed 'target' branch is executed, this is fine.
Some such workflows switch to the code from 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. Therefore we recommend against doing this, and suggest to split the job into an untrusted pull_request-triggered part and a trusted workflow_run part as documented in the next section:
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.
...
- Always extract into a directory separate from the trusted code in a step before checking out said trusted code. This stops files extracted from the archive from clobbering trusted code.
- A separate directory can also prevent files in the artifact impersonating often used python modules like
pipas runningpython -m pip ...would execute a pip.py file in the cwd - Validate any content you retrieve from an artifact before you use it to avoid command injection, especially in steps using
bashand Github Actions macros.- This includes using
caton such files as well as putting their content into environment variables (a popular exploit is to modifyLD_PRELOAD, some examples ), step outputs to use via${{ steps.id.outputs.sus_content }}to be used in e.g.ifin bash
- This includes using
An example of a job that is split into two parts like this is the NuttX PR labeler, https://github.com/apache/nuttx/blob/master/.github/workflows/labeler.yml and https://github.com/apache/nuttx/blob/master/.github/workflows/pr_labeler.yml.
Builds triggered with issue_comment
...
Workflows triggered by workflow_run only run when this workflow also exists on the main branch, so removing/renaming it on the main branch may also help there.
Further mitigations
...
- NEVER directly run code that might come with "forked" PRs in your workflows. There are certain exotic (but useful) workflows that are dangerous. For example, with "workflow_run" you might need to cancel duplicate workflows. Those workflows by default run with "master" code, but sometimes you might need to check out the incoming PR code for those. The host environment can have access (in various ways) to the "WRITE" GITHUB_TOKEN that has permission to modify your repository WITHOUT RESTRICTION OR NOTIFICATION. NEVER run the code that is checked out from the PR in your host environment. If you need to, run it in Docker Container to provide isolation from the host environment to avoid the "write" access leaking to users who prepare such a PR from their fork.
- NEVER install and run 3rd-party dependencies in the host of your build workflow code. Again there are ways those dependencies can obtain the "WRITE" GITHUB_TOKEN and change anything in your repository without your knowledge. There are very common "schedule" and "push" workflows that are especially prone to such abuse. Those run with "WRITE" access, and again there are ways to obtain the GitHub Token by these Actions and code that runs in your workflow. If you execute any 3rd-party code, run it in Docker containers to keep isolation from your "build" host environment to avoid leaking "write" access to those 3rd parties.
- If you REALLY HAVE TO run untrusted code (for example as part of your build steps) - you should only do it inside a docker container that you should not pass any credentials to.
- If you build images from Dockerfile that is untrusted make sure you use .dockerignore which is not coming from the PR, which Ignores everything from context by default. Add
**as the first line and only adds (via!directory_pathor!file_path) the files that you need during the build