Understand the security status of GitHub Actions workflows and how to mitigate the risk.
We recently published a report, called The State of GitHub Actions Security, which analyzes the security posture of GitHub Actions workflows and custom GitHub Actions. This report is based on an analysis of 2,500,000 GitHub Actions workflow files belonging to 553,000 organizations and personal users.
Some notable findings include the insecurity of the building blocks of GitHub Actions workflows.
All GitHub Actions automations are handled via workflows. The building blocks of the workflows include:
Triggers control when a workflow should run. GitHub Actions provide 36 event types that trigger workflows.
The most used triggers are shown in the table below.
Some triggers inherently present more risk than others, for instance, pull_request_target and workflow_run. We found thousands of occurrences of both these triggers, listed in the table below.
Although useful, pull_request_target in particular opens the door to a wide range of security issues, including RCE.
This workflow checks out the pull_request code and then builds it (in a privileged context). Since the code is from an untrusted source (fork), it leads to RCE in a privileged context.
We found 2,341 pull_request_target workflows vulnerable to attacks like remote code execution.
In this example of workflow_run:
The workflow runs when ‘Run Tests’ workflow completes.
A ‘workflow_run’ triggered workflow acts as a triggered workflow that is executed when another workflow completes, in a privileged context (has access to secrets and tokens). Normally, it is used to chain workflows. In public repositories, it is used to process untrusted pull requests from forks. The fork pull request executes the “dangerous parts” and then triggers the workflow_run workflow to finish the processing.
We found 1,561 workflow_run workflows vulnerable to attacks like remote code execution.
When possible, avoid using dangerous triggers. If you can’t avoid them, use the following mitigation strategies:
Jobs and steps are the building blocks of a GitHub Actions workflow. A job is composed of several steps, while steps perform the actual work.
This build job is composed of two steps, one that downloads the repository source code and another that performs the actual build.
Steps can reference prebuilt workflows from third-party entities, such as open source builders and vendors. When a step uses the “uses: repository_name@ref” clause, the Actions engine will download ‘repository_name’ at the specified ‘ref’ and execute it.
There a several options to reference an Action:
Pro: The most secure way to reference a third-party Action, it guarantees the third-party Action version specified.
Con: The Actions are not updated automatically.
Pro: Using a published release of the Action, it receives updates only if the workflow author intends it to.
Con: The Action can change without the dependent workflow’s knowledge.
(For more explanation about the risks of mutable tags, see What Are Immutable Tags And Can They Protect You From Supply Chain Attacks?)
This is insecure, as the workflow will use any code from the third-party Action without control.
This is the most insecure way to reference a third-party Action, and imposes the same risk as “reference to the main branch,” with the additional risk that unlike the main branch, other branches usually don’t have security guardrails that validate their quality, such as code review and code scanning.
A less common way to use custom Actions is to use prebuilt docker images. This method is not prevalent in the GitHub Actions ecosystem and imposes risk on the image consumers because they can’t access the third-party Action source code (without reverse engineering the image).
98.4 percent of the references used by jobs and steps are not following the best practice of dependency pinning, which specifies which package or library an Action can rely on.
Dependency pinning in GitHub Actions (and in general) is crucial for ensuring workflows are stable and reproduceable. By pinning dependencies, you specify the exact versions of the external packages or libraries your Actions rely on. This practice guards against unexpected changes or updates that could potentially introduce breaking changes, compatibility issues, or security vulnerabilities.
The GitHub Actions runner is the engine that executes the workflow definition. It both communicates with the GitHub server to obtain credentials and configurations and reads the user workflow file and executes it according to the definitions. The runner code is open-source and hosted on GitHub https://github.com/actions/runner.
There are two ways to use runners:
Self-hosted runners pose significant security risks (see blog on self-hosted runner security here), especially if untrusted workflows run on them. Malicious programs may run on the machine, and it’s possible for the runner sandbox to be escaped, exposing access to the machine’s network environment. Additionally, unwanted or dangerous data can be persisted on the machine.
This is especially critical for public repositories since they may allow the organization’s users to execute workflows on the runners used by the public repositories.
We found 44,803 public repositories using hosted runners.
We recommend only using self-hosted runners with private repositories. Forks of your public repository could potentially run dangerous code on your self-hosted runner machine by creating a pull request that executes the code in a workflow. GitHub-hosted runners, on the other hand, are clean, isolated virtual machines that are destroyed at the end of the job execution and do not pose the same risks.
Each workflow run is assigned a GitHub personal access token scoped to the current repository that enables it to communicate with a GitHub API. By default, this token is highly privileged and has access to the following scopes and corresponding APIs:
If a workflow is compromised, the token can be used to perform malicious actions and even take over the repository.
Therefore, it is important that workflow authors use the “permission” key to specify the scope their workflow requires.
Legit found that only 14 percent of all workflows limit token permissions; without these limits, the token could be used to perform malicious actions or take over the repository.
Download the full report to get more details on GitHub Actions security, including:
*** This is a Security Bloggers Network syndicated blog from Legit Security Blog authored by Noam Dotan. Read the original post at: https://www.legitsecurity.com/blog/security-of-the-building-blocks-of-github-actions-workflows