Skip to content

Commit e83841b

Browse files
committed
fixes
1 parent a282818 commit e83841b

17 files changed

+126
-229
lines changed

ql/src/Security/CWE-088/ArgumentInjectionCritical.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Passing user-controlled arguments to certain commands in the context of `Run` steps may lead to arbitrary code execution.
66

7-
Argument injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.
7+
Argument injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token may have write access to the repository, allowing the attacker to make changes to the repository.
88

99
## Recommendations
1010

ql/src/Security/CWE-088/ArgumentInjectionMedium.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Passing user-controlled arguments to certain commands in the context of `Run` steps may lead to arbitrary code execution.
66

7-
Argument injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.
7+
Argument injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token may have write access to the repository, allowing the attacker to make changes to the repository.
88

99
## Recommendations
1010

ql/src/Security/CWE-094/CodeInjectionCritical.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Using user-controlled input in GitHub Actions may lead to code injection in contexts like _run:_ or _script:_.
66

7-
Code injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.
7+
Code injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token may have write access to the repository, allowing an attacker to make changes to the repository.
88

99
## Recommendations
1010

@@ -16,7 +16,7 @@ It is also recommended to limit the permissions of any tokens used by a workflow
1616

1717
### Incorrect Usage
1818

19-
The following example lets a user inject an arbitrary shell command:
19+
The following example lets attackers inject an arbitrary shell command:
2020

2121
```yaml
2222
on: issue_comment

ql/src/Security/CWE-094/CodeInjectionMedium.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Using user-controlled input in GitHub Actions may lead to code injection in contexts like _run:_ or _script:_.
66

7-
Code injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token might have write access to the repository, allowing an attacker to use the token to make changes to the repository.
7+
Code injection in GitHub Actions may allow an attacker to exfiltrate any secrets used in the workflow and the temporary GitHub repository authorization token. The token may have write access to the repository, allowing an attacker to make changes to the repository.
88

99
## Recommendations
1010

@@ -16,7 +16,7 @@ It is also recommended to limit the permissions of any tokens used by a workflow
1616

1717
### Incorrect Usage
1818

19-
The following example lets a user inject an arbitrary shell command:
19+
The following example lets attackers inject an arbitrary shell command:
2020

2121
```yaml
2222
on: issue_comment

ql/src/Security/CWE-275/MissingActionsPermissions.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
## Description
44

5-
A GitHub Actions job or workflow hasn't set explicit permissions to restrict privileges to the workflow job.
6-
A workflow job by default without the `permissions` key or a root workflow `permissions` will run with the default permissions defined at the repository level. For organizations created before February 2023, including many significant OSS projects and corporations, the default permissions grant read-write access to repositories, and new repositories inherit these old, insecure permissions.
5+
If a GitHub Actions job or workflow has no explicit permissions set, then the repository permissions are used. Repositories created under organizations inherit the organization permissions. The organizations or repositories created before February 2023 have the default permissions set to read-write. Often these permissions do not adhere to the principle of least privilege and can be reduced to read-only, leaving the `write` permission only to a specific types as `issues: write` or `pull-requests: write`.
76

87
## Recommendations
98

10-
Add the `permissions` key to the job or workflow (applied to all jobs) and set the permissions to the least privilege required to complete the task:
9+
Add the `permissions` key to the job or the root of workflow (in this case it is applied to all jobs in the workflow that do not have their own `permissions` key) and assign the least privileges required to complete the task:
1110

1211
```yaml
1312
name: "My workflow"

ql/src/Security/CWE-285/ImproperAccessControl.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22

33
## Description
44

5-
An authorization check may not be properly implemented, allowing an attacker to mutate the code after it has been reviewed.
5+
Sometimes labels are used to approve GitHub Actions. An authorization check may not be properly implemented, allowing an attacker to mutate the code after it has been reviewed and approved by label.
66

77
## Recommendations
88

9-
When using Label gates, make sure that the code cannot be modified after it has been reviewed and the label has been set.
9+
When using labels, make sure that the code cannot be modified after it has been reviewed and the label has been set.
1010

1111
## Examples
1212

1313
### Incorrect Usage
1414

15-
The following example shows a job that requires the label `safe to test` to be set before running untrusted code. However, the workflow gets triggered on `synchronize` activity type and, therefore, it will get triggered every time there is a change in the Pull Request. An attacker can modify the code of the Pull Request after the code has been reviewed and the label has been set.
15+
The following example shows a job that requires the label `safe to test` to be set before running untrusted code. There are two problems with the code:
16+
17+
1. The workflow gets triggered on `synchronize` activity type and, therefore, it will get triggered every time there is a change in the Pull Request. An attacker can modify the code of the Pull Request after the code has been reviewed and the label has been set. The workflow will be triggered every time a new change is added to the Pull Request.
18+
2. The workflow uses `ref: ${{ github.event.pull_request.head.ref }}` for checkout, which is a branch name of the Pull Request. There is a window of opportunity for the attacker to modify their branch after the Pull Request is labeled, but before the workflow starts and runs the checkout.
1619

1720
```yaml
1821
on:
@@ -33,7 +36,7 @@ jobs:
3336
3437
### Correct Usage
3538
36-
Make sure that the workflow only gets triggered when the label is set and use an inmutable commit (`github.event.pull_request.head.sha`) instead of a mutable reference.
39+
Make sure that the workflow only gets triggered when the label is set and use an immutable commit (`github.event.pull_request.head.sha`) instead of a mutable reference.
3740

3841
```yaml
3942
on:

ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## Description
44

5-
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache, potentially leading to code execution in privileged workflows.
5+
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache from unprivileged workflow, potentially leading to code execution in privileged workflows.
66

77
An attacker with the ability to run code in the context of the default branch (e.g. through Code Injection or Execution of Untrusted Code) can exploit this to:
88

9-
1. Steal the cache access token and URL
10-
2. Fill the cache to trigger eviction of legitimate entries
11-
3. Poison cache entries with malicious payloads
12-
4. Achieve code execution in privileged workflows that restore the poisoned cache
9+
1. Steal the cache access token and URL.
10+
2. Overflow the cache to trigger eviction of legitimate entries.
11+
3. Poison cache entries with malicious payloads.
12+
4. Achieve code execution in privileged workflows that restore the poisoned cache.
1313

1414
This allows lateral movement from low-privileged to high-privileged workflows within a repository.
1515

@@ -27,11 +27,11 @@ Due to the above design, if something is cached in the context of the default br
2727

2828
1. Avoid using caching in workflows that handle sensitive operations like releases.
2929
2. If caching must be used:
30-
- Validate restored cache contents before use
31-
- Use short-lived, workflow-specific cache keys
32-
- Clear caches regularly
33-
3. Implement strict isolation between untrusted and privileged workflow execution:
34-
4. Never run untrusted code in the context of the default branch
30+
- Validate restored cache contents before use.
31+
- Use short-lived, workflow-specific cache keys.
32+
- Clear caches regularly.
33+
3. Implement strict isolation between untrusted and privileged workflow execution.
34+
4. Never run untrusted code in the context of the default branch.
3535
5. Sign the cache value cryptographically and verify the signature before usage.
3636

3737
## Examples

ql/src/Security/CWE-349/CachePoisoningViaDirectCache.md

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## Description
44

5-
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache, potentially leading to code execution in privileged workflows.
5+
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache from unprivileged workflow, potentially leading to code execution in privileged workflows.
66

77
An attacker with the ability to run code in the context of the default branch (e.g. through Code Injection or Execution of Untrusted Code) can exploit this to:
88

9-
1. Steal the cache access token and URL
10-
2. Fill the cache to trigger eviction of legitimate entries
11-
3. Poison cache entries with malicious payloads
12-
4. Achieve code execution in privileged workflows that restore the poisoned cache
9+
1. Steal the cache access token and URL.
10+
2. Overflow the cache to trigger eviction of legitimate entries.
11+
3. Poison cache entries with malicious payloads.
12+
4. Achieve code execution in privileged workflows that restore the poisoned cache.
1313

1414
This allows lateral movement from low-privileged to high-privileged workflows within a repository.
1515

@@ -27,11 +27,11 @@ Due to the above design, if something is cached in the context of the default br
2727

2828
1. Avoid using caching in workflows that handle sensitive operations like releases.
2929
2. If caching must be used:
30-
- Validate restored cache contents before use
31-
- Use short-lived, workflow-specific cache keys
32-
- Clear caches regularly
33-
3. Implement strict isolation between untrusted and privileged workflow execution:
34-
4. Never run untrusted code in the context of the default branch
30+
- Validate restored cache contents before use.
31+
- Use short-lived, workflow-specific cache keys.
32+
- Clear caches regularly.
33+
3. Implement strict isolation between untrusted and privileged workflow execution.
34+
4. Never run untrusted code in the context of the default branch.
3535
5. Sign the cache value cryptographically and verify the signature before usage.
3636

3737
## Examples
@@ -69,13 +69,12 @@ jobs:
6969
7070
### Correct Usage
7171
72-
The following workflow is not checking out untrusted files and, therefore, is caching trusted files only.
72+
The following workflow checking out untrusted files, but the cache is scoped to the Pull Request.
7373
7474
```yaml
7575
name: Secure Workflow
7676
on:
77-
issue_comment:
78-
types: [created]
77+
pull_request:
7978

8079
jobs:
8180
pr-comment:
@@ -94,6 +93,34 @@ jobs:
9493
restore-keys: ${{ runner.os }}-pip-
9594
```
9695
96+
Note, that the example above doesn't allow using secrets if the Pull Request originates from a fork. In case secrets are needed, `pull_request_target` with labels as `safe to test` can be used, but the code in Pull Request must be manually reviewed before applying the label.
97+
98+
```yaml
99+
name: Secure Workflow
100+
on:
101+
pull_request_target:
102+
types: [labeled]
103+
104+
jobs:
105+
pr-comment:
106+
if: contains(github.event.pull_request.labels.*.name, 'safe to test')
107+
permissions: read-all
108+
runs-on: ubuntu-latest
109+
steps:
110+
- uses: actions/checkout@v3
111+
with:
112+
ref: ${{ github.event.pull_request.head.sha}}
113+
- name: Set up Python 3.10
114+
uses: actions/setup-python@v5
115+
- name: Cache pip dependencies
116+
uses: actions/cache@v4
117+
id: cache-pip
118+
with:
119+
path: ~/.cache/pip
120+
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
121+
restore-keys: ${{ runner.os }}-pip-
122+
```
123+
97124
## References
98125

99126
- [The Monsters in Your Build Cache – GitHub Actions Cache Poisoning](https://adnanthekhan.com/2024/05/06/the-monsters-in-your-build-cache-github-actions-cache-poisoning/)

ql/src/Security/CWE-349/CachePoisoningViaPoisonableStep.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## Description
44

5-
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache, potentially leading to code execution in privileged workflows.
5+
GitHub Actions cache poisoning is a technique that allows an attacker to inject malicious content into the Action's cache from unprivileged workflow, potentially leading to code execution in privileged workflows.
66

77
An attacker with the ability to run code in the context of the default branch (e.g. through Code Injection or Execution of Untrusted Code) can exploit this to:
88

9-
1. Steal the cache access token and URL
10-
2. Fill the cache to trigger eviction of legitimate entries
11-
3. Poison cache entries with malicious payloads
12-
4. Achieve code execution in privileged workflows that restore the poisoned cache
9+
1. Steal the cache access token and URL.
10+
2. Overflow the cache to trigger eviction of legitimate entries.
11+
3. Poison cache entries with malicious payloads.
12+
4. Achieve code execution in privileged workflows that restore the poisoned cache.
1313

1414
This allows lateral movement from low-privileged to high-privileged workflows within a repository.
1515

@@ -27,11 +27,11 @@ Due to the above design, if something is cached in the context of the default br
2727

2828
1. Avoid using caching in workflows that handle sensitive operations like releases.
2929
2. If caching must be used:
30-
- Validate restored cache contents before use
31-
- Use short-lived, workflow-specific cache keys
32-
- Clear caches regularly
33-
3. Implement strict isolation between untrusted and privileged workflow execution:
34-
4. Never run untrusted code in the context of the default branch
30+
- Validate restored cache contents before use.
31+
- Use short-lived, workflow-specific cache keys.
32+
- Clear caches regularly.
33+
3. Implement strict isolation between untrusted and privileged workflow execution.
34+
4. Never run untrusted code in the context of the default branch.
3535
5. Sign the cache value cryptographically and verify the signature before usage.
3636

3737
## Examples
@@ -59,7 +59,7 @@ jobs:
5959
6060
### Correct Usage
6161
62-
The following workflow runs untrusted code in a non-privileged job and in the context of a non-default branch.
62+
The following workflow runs untrusted code in a non-privileged job and the cache is scoped to the Pull Request branch.
6363
6464
```yaml
6565
name: Secure Workflow

ql/src/Security/CWE-367/UntrustedCheckoutTOCTOUCritical.md

Lines changed: 3 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Untrusted Checkout TOCTOU
1+
# Untrusted Checkout TOCTOU (Time-of-check to time-of-use)
22

33
## Description
44

@@ -8,77 +8,11 @@ Untrusted Checkout is protected by a security check but the checked-out branch c
88

99
Verify that the code has not been modified after the security check. This may be achieved differently depending on the type of check:
1010

11-
- Issue Ops: Verify that Commit containing the code to be executed was commited **before** then date the of the comment.
1211
- Deployment Environment Approval: Make sure to use a non-mutable reference to the code to be executed. For example use a `sha` instead of a `ref`.
1312
- Label Gates: Make sure to use a non-mutable reference to the code to be executed. For example use a `sha` instead of a `ref`.
1413

1514
## Examples
1615

17-
### Incorrect Usage (Issue Ops)
18-
19-
The following workflow runs untrusted code after either a member or admin of the repository comments on a Pull Request with the text `/run-tests`. Although it may seem secure, the workflow is checking out a mutable reference (`${{ steps.comment-branch.outputs.head_ref }}`) and therefore the code can be mutated between the time of check (TOC) and the time of use (TOU).
20-
21-
```yaml
22-
name: Comment Triggered Test
23-
on:
24-
issue_comment:
25-
types: [created]
26-
jobs:
27-
benchmark:
28-
name: Integration Tests
29-
if: ${{ github.event.issue.pull_request && contains(fromJson('["MEMBER", "OWNER"]'), github.event.comment.author_association) && startsWith(github.event.comment.body, '/run-tests ') }}
30-
permissions: "write-all"
31-
runs-on: [ubuntu-latest]
32-
steps:
33-
- name: Get PR branch
34-
uses: xt0rted/pull-request-comment-branch@v2
35-
id: comment-branch
36-
- name: Checkout PR branch
37-
uses: actions/checkout@v3
38-
with:
39-
ref: ${{ steps.comment-branch.outputs.head_ref }}
40-
- run: ./cmd
41-
```
42-
43-
### Correct Usage (Issue Ops)
44-
45-
In the following example, the workflow checks if the latest commit of the Pull Request head was commited **before** the comment on the Pull Request, therefore ensuring that it was not mutated after the check.
46-
47-
```yaml
48-
name: Comment Triggered Test
49-
on:
50-
issue_comment:
51-
types: [created]
52-
jobs:
53-
benchmark:
54-
name: Integration Tests
55-
if: ${{ github.event.issue.pull_request && contains(fromJson('["MEMBER", "OWNER"]'), github.event.comment.author_association) && startsWith(github.event.comment.body, '/run-tests ') }}
56-
permissions: "write-all"
57-
runs-on: [ubuntu-latest]
58-
steps:
59-
- name: Get PR Info
60-
id: pr
61-
env:
62-
PR_NUMBER: ${{ github.event.issue.number }}
63-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64-
GH_REPO: ${{ github.repository }}
65-
COMMENT_AT: ${{ github.event.comment.created_at }}
66-
run: |
67-
pr="$(gh api /repos/${GH_REPO}/pulls/${PR_NUMBER})"
68-
head_sha="$(echo "$pr" | jq -r .head.sha)"
69-
pushed_at="$(echo "$pr" | jq -r .pushed_at)"
70-
if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
71-
echo "Updating is not allowed because the PR was pushed to (at $pushed_at) after the triggering comment was issued (at $COMMENT_AT)"
72-
exit 1
73-
fi
74-
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
75-
- name: Checkout PR branch
76-
uses: actions/checkout@v3
77-
with:
78-
ref: ${{ steps.pr.outputs.head_sha }}
79-
- run: ./cmd
80-
```
81-
8216
### Incorrect Usage (Deployment Environment Approval)
8317

8418
The following workflow uses a Deployment Environment which may be configured to require an approval. However, it check outs the code pointed to by the Pull Request branch reference. At attacker could submit legitimate code for review and then change it once it gets approved.
@@ -102,7 +36,7 @@ jobs:
10236
10337
### Correct Usage (Deployment Environment Approval)
10438
105-
Use inmutable references (Commit SHA) to make sure that the reviewd code does not change between the check and the use.
39+
Use immutable references (Commit SHA) to make sure that the reviewed code does not change between the check and the use.
10640
10741
```yml
10842
on:
@@ -144,7 +78,7 @@ jobs:
14478
14579
### Correct Usage (Label Gates)
14680
147-
Use inmutable references (Commit SHA) to make sure that the reviewd code does not change between the check and the use.
81+
Use immutable references (Commit SHA) to make sure that the reviewed code does not change between the check and the use.
14882
14983
```yaml
15084
on:

0 commit comments

Comments
 (0)