Skip to content

Commit 3ea449b

Browse files
committed
Update query help
1 parent baabf3d commit 3ea449b

File tree

1 file changed

+33
-22
lines changed

1 file changed

+33
-22
lines changed

actions/ql/src/Security/CWE-094/CodeInjectionLow.md

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,50 @@
11
## Overview
22

3-
Using user-controlled input in GitHub Actions may lead to code injection in contexts like _run:_ or _script:_.
3+
Using the output of a previous workflow step in GitHub Actions may lead to code injection in contexts like _run:_ or _script:_ if the step output can be controlled by a malicious actor. This alert does not always indicate a vulnerability, as step outputs are often derived from trusted sources and cannot be controlled by an attacker. However, if the step output originates from user-controlled data (such as issue comments, pull request titles, or commit messages), it may be exploitable.
44

5-
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.
5+
If a step output is user-controlled, 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.
66

77
## Recommendation
88

9-
The best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not _${{ env.VAR }}_).
9+
First, determine whether the step output can actually be controlled by an attacker. Trace the data flow from the step that sets the output to understand where the value originates. If the output is derived from trusted sources (such as hardcoded values, repository settings, or authenticated API responses), the risk is minimal.
10+
11+
If the step output can be user-controlled, the best practice to avoid code injection vulnerabilities in GitHub workflows is to set the untrusted input value of the expression to an intermediate environment variable and then use the environment variable using the native syntax of the shell/script interpreter (that is, not _${{ env.VAR }}_).
1012

1113
It is also recommended to limit the permissions of any tokens used by a workflow such as the GITHUB_TOKEN.
1214

1315
## Example
1416

1517
### Incorrect Usage
1618

17-
The following example lets attackers inject an arbitrary shell command:
19+
The following example lets attackers inject an arbitrary shell command if output `message` of the step `get-message` is derived from user-controlled data:
1820

1921
```yaml
20-
on: issue_comment
21-
2222
jobs:
23-
echo-body:
23+
echo-message:
2424
runs-on: ubuntu-latest
2525
steps:
26+
- id: get-message
27+
run: |
28+
# If this value comes from user input, it is vulnerable
29+
echo "message=$USER_INPUT" >> $GITHUB_OUTPUT
2630
- run: |
27-
echo '${{ github.event.comment.body }}'
31+
echo '${{ steps.get-message.outputs.message }}'
2832
```
2933
3034
The following example uses an environment variable, but **still allows the injection** because of the use of expression syntax:
3135
3236
```yaml
33-
on: issue_comment
34-
3537
jobs:
36-
echo-body:
38+
echo-message:
3739
runs-on: ubuntu-latest
3840
steps:
39-
- env:
40-
BODY: ${{ github.event.issue.body }}
41-
run: |
42-
echo '${{ env.BODY }}'
41+
- id: get-message
42+
run: |
43+
echo "message=$USER_INPUT" >> $GITHUB_OUTPUT
44+
- env:
45+
MESSAGE: ${{ steps.get-message.outputs.message }}
46+
run: |
47+
echo '${{ env.MESSAGE }}'
4348
```
4449
4550
### Correct Usage
@@ -48,28 +53,34 @@ The following example uses shell syntax to read the environment variable and wil
4853
4954
```yaml
5055
jobs:
51-
echo-body:
56+
echo-message:
5257
runs-on: ubuntu-latest
5358
steps:
59+
- id: get-message
60+
run: |
61+
echo "message=$USER_INPUT" >> $GITHUB_OUTPUT
5462
- env:
55-
BODY: ${{ github.event.issue.body }}
63+
MESSAGE: ${{ steps.get-message.outputs.message }}
5664
run: |
57-
echo "$BODY"
65+
echo "$MESSAGE"
5866
```
5967
6068
The following example uses `process.env` to read environment variables within JavaScript code.
6169

6270
```yaml
6371
jobs:
64-
echo-body:
72+
echo-message:
6573
runs-on: ubuntu-latest
6674
steps:
67-
- uses: uses: actions/github-script@v4
75+
- id: get-message
76+
run: |
77+
echo "message=$USER_INPUT" >> $GITHUB_OUTPUT
78+
- uses: actions/github-script@v4
6879
env:
69-
BODY: ${{ github.event.issue.body }}
80+
MESSAGE: ${{ steps.get-message.outputs.message }}
7081
with:
7182
script: |
72-
const { BODY } = process.env
83+
const { MESSAGE } = process.env
7384
...
7485
```
7586

0 commit comments

Comments
 (0)