Skip to content

Commit 483c1f2

Browse files
committed
Preserve untrusted checkout alert coverage
1 parent 3ba6b85 commit 483c1f2

5 files changed

Lines changed: 78 additions & 14 deletions

File tree

actions/ql/lib/ext/config/poisonable_steps.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ extensions:
6767
# TODO: It could also be in the form of `dir/cmd`
6868
- ["(\\.\\/[^\\s]+)\\b", 1] # eg: ./venv/bin/activate
6969
- ["(\\.\\s+[^\\s]+)\\b", 1] # eg: . venv/bin/activate
70-
# An Actions expression may contain spaces while remaining one shell operand.
71-
- ["(source|sh|bash|zsh|fish)\\s+((?:['\"]?\\$\\{\\{(?:[^}]|}(?!}))*+\\}\\}['\"]?[^\\s]*|[^\\s]+)\\b[\"']?)", 2]
70+
# A workspace expression may contain spaces while remaining one shell operand.
71+
- ["(source|sh|bash|zsh|fish)\\s+((?:['\"]?\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}['\"]?[^\\s]*|[^\\s]+)\\b[\"']?)", 2]
7272
- ["(node)\\s+([^\\s]+)(\\.js|\\.ts)\\b", 2]
7373
- ["(python[\\d\\.]*)\\s+([^\\s]+)\\.py\\b", 2]
7474
- ["(python[\\d\\.]*)\\s+-m\\s+([A-Za-z_][\\w\\.]*)\\b", 2] # eg: pythonX -m anything(dir or file)

actions/ql/src/Security/CWE-829/UntrustedCheckoutCritical.ql

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ bindingset[path]
4545
private predicate isWorkspaceContextExecutionPath(string path) {
4646
// Actions evaluates contexts before the resulting command is passed to the shell.
4747
path.regexpMatch([
48-
"^\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}/.*",
49-
"^\"\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}/.*\"$",
50-
"^'\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}/.*'$",
51-
"^\"\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}\"/.*",
52-
"^'\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}'/.*"
48+
"^\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}/.*",
49+
"^\"\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}/.*\"$",
50+
"^'\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}/.*'$",
51+
"^\"\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}\"/.*",
52+
"^'\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}'/.*"
5353
])
5454
}
5555

@@ -63,7 +63,7 @@ private string normalizeWorkspaceExecutionPath(string path) {
6363
or
6464
isWorkspaceContextExecutionPath(path) and
6565
result =
66-
path.regexpReplaceAll("^[\"']?\\$\\{\\{\\s*github\\.workspace\\s*\\}\\}[\"']?/",
66+
path.regexpReplaceAll("^[\"']?\\$\\{\\{\\s*github(?:\\.workspace|\\[\\s*'workspace'\\s*\\])\\s*\\}\\}[\"']?/",
6767
"GITHUB_WORKSPACE/").regexpReplaceAll("[\"']$", "")
6868
}
6969

@@ -155,11 +155,8 @@ where
155155
(
156156
// Check if the poisonable step is a local script execution step
157157
// and the path of the command or script matches the path of the downloaded artifact
158-
// A shell assignment breaks the default-workspace provenance of the environment variable.
159-
not (
160-
isWorkspaceEnvironmentExecutionPath(poisonable.(LocalScriptExecutionRunStep).getRawPath()) and
161-
poisonable.(LocalScriptExecutionRunStep).getScript().getAnAssignment("GITHUB_WORKSPACE", _)
162-
) and
158+
// The shell model has no control-flow-sensitive assignment relation, so an assignment cannot
159+
// safely disprove that the workspace value reaches this execution.
163160
checkoutContainsPath(checkout, poisonable.(LocalScriptExecutionRunStep).getRawPath(),
164161
poisonable.(LocalScriptExecutionRunStep).getPath())
165162
or

actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_paths.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,59 @@ jobs:
220220
- run: bash ${{ github.workspace }}/candidate/../trusted.sh
221221
- run: bash ${{ github.workspace }}/../candidate/build.sh
222222
- run: bash ${{ github.action_path }}/candidate/build.sh
223+
224+
workspace-context-index-syntax:
225+
runs-on: ubuntu-latest
226+
steps:
227+
- uses: actions/checkout@v4.2.2
228+
with:
229+
repository: ${{ github.event.pull_request.head.repo.full_name }}
230+
ref: ${{ github.event.pull_request.head.sha }}
231+
path: candidate
232+
- run: bash "${{ github['workspace'] }}/candidate/build.sh"
233+
234+
unresolved-workspace-expression:
235+
runs-on: ubuntu-latest
236+
steps:
237+
- uses: actions/checkout@v4.2.2
238+
with:
239+
repository: ${{ github.event.pull_request.head.repo.full_name }}
240+
ref: ${{ github.event.pull_request.head.sha }}
241+
path: candidate
242+
- run: bash "${{ github.action_path }}/candidate/build.sh"
243+
244+
workspace-assignment-after-use:
245+
runs-on: ubuntu-latest
246+
steps:
247+
- uses: actions/checkout@v4.2.2
248+
with:
249+
repository: ${{ github.event.pull_request.head.repo.full_name }}
250+
ref: ${{ github.event.pull_request.head.sha }}
251+
path: candidate
252+
- run: |
253+
bash "$GITHUB_WORKSPACE/candidate/build.sh"
254+
GITHUB_WORKSPACE=/tmp
255+
256+
conditional-workspace-assignment:
257+
runs-on: ubuntu-latest
258+
steps:
259+
- uses: actions/checkout@v4.2.2
260+
with:
261+
repository: ${{ github.event.pull_request.head.repo.full_name }}
262+
ref: ${{ github.event.pull_request.head.sha }}
263+
path: candidate
264+
- run: |
265+
if false; then
266+
GITHUB_WORKSPACE=/tmp
267+
fi
268+
bash "$GITHUB_WORKSPACE/candidate/build.sh"
269+
270+
workspace-assignment-after-use-same-line:
271+
runs-on: ubuntu-latest
272+
steps:
273+
- uses: actions/checkout@v4.2.2
274+
with:
275+
repository: ${{ github.event.pull_request.head.repo.full_name }}
276+
ref: ${{ github.event.pull_request.head.sha }}
277+
path: candidate
278+
- run: bash $GITHUB_WORKSPACE/candidate/build.sh; GITHUB_WORKSPACE=/tmp

actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,12 @@ edges
378378
| .github/workflows/untrusted_checkout_paths.yml:218:9:219:6 | Run Step | .github/workflows/untrusted_checkout_paths.yml:219:9:220:6 | Run Step |
379379
| .github/workflows/untrusted_checkout_paths.yml:219:9:220:6 | Run Step | .github/workflows/untrusted_checkout_paths.yml:220:9:221:6 | Run Step |
380380
| .github/workflows/untrusted_checkout_paths.yml:220:9:221:6 | Run Step | .github/workflows/untrusted_checkout_paths.yml:221:9:222:6 | Run Step |
381-
| .github/workflows/untrusted_checkout_paths.yml:221:9:222:6 | Run Step | .github/workflows/untrusted_checkout_paths.yml:222:9:222:63 | Run Step |
381+
| .github/workflows/untrusted_checkout_paths.yml:221:9:222:6 | Run Step | .github/workflows/untrusted_checkout_paths.yml:222:9:224:2 | Run Step |
382+
| .github/workflows/untrusted_checkout_paths.yml:227:9:232:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:232:9:234:2 | Run Step |
383+
| .github/workflows/untrusted_checkout_paths.yml:237:9:242:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:242:9:244:2 | Run Step |
384+
| .github/workflows/untrusted_checkout_paths.yml:247:9:252:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:252:9:256:2 | Run Step |
385+
| .github/workflows/untrusted_checkout_paths.yml:259:9:264:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:264:9:270:2 | Run Step |
386+
| .github/workflows/untrusted_checkout_paths.yml:273:9:278:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:278:9:278:78 | Run Step |
382387
| .github/workflows/untrusted_checkout_permission_check_reusable2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable2.yml:16:9:22:2 | Run Step |
383388
| .github/workflows/untrusted_checkout_permission_check_reusable.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable.yml:16:9:22:2 | Run Step |
384389
| .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:8:9:16:6 | Uses Step: checkAccess | .github/workflows/untrusted_checkout_permission_check_reusable_level2.yml:16:9:22:2 | Run Step |
@@ -452,10 +457,15 @@ edges
452457
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:207:9:208:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
453458
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:208:9:209:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
454459
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:209:9:210:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
460+
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:211:9:214:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
455461
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:214:9:215:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
456462
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:215:9:216:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
457463
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:216:9:217:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
458464
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:217:9:218:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
459465
| .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:193:9:198:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:218:9:219:6 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
466+
| .github/workflows/untrusted_checkout_paths.yml:227:9:232:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:227:9:232:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:232:9:234:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
467+
| .github/workflows/untrusted_checkout_paths.yml:247:9:252:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:247:9:252:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:252:9:256:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
468+
| .github/workflows/untrusted_checkout_paths.yml:259:9:264:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:259:9:264:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:264:9:270:2 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
469+
| .github/workflows/untrusted_checkout_paths.yml:273:9:278:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:273:9:278:6 | Uses Step | .github/workflows/untrusted_checkout_paths.yml:278:9:278:78 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
460470
| .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:36:9:41:6 | Uses Step | .github/workflows/untrusted_checkout_permissions_check.yml:41:9:41:22 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_permissions_check.yml:2:3:2:21 | pull_request_target | pull_request_target |
461471
| .github/workflows/workflow_run_untrusted_checkout_path.yml:12:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_path.yml:12:9:16:6 | Uses Step | .github/workflows/workflow_run_untrusted_checkout_path.yml:16:9:16:40 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/workflow_run_untrusted_checkout_path.yml:4:3:4:14 | workflow_run | workflow_run |

actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutHigh.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
| .github/workflows/pr-workflow.yml:444:9:449:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/pr-workflow-fork.yaml:7:3:7:21 | pull_request_target | pull_request_target |
1818
| .github/workflows/test13.yml:20:7:25:4 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/test13.yml:2:3:2:15 | issue_comment | issue_comment |
1919
| .github/workflows/untrusted_checkout2.yml:14:9:19:72 | Run Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout2.yml:1:5:1:17 | issue_comment | issue_comment |
20+
| .github/workflows/untrusted_checkout_paths.yml:237:9:242:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/untrusted_checkout_paths.yml:4:3:4:21 | pull_request_target | pull_request_target |
2021
| .github/workflows/workflow_run_untrusted_checkout.yml:13:9:16:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/workflow_run_untrusted_checkout.yml:2:3:2:14 | workflow_run | workflow_run |
2122
| .github/workflows/workflow_run_untrusted_checkout.yml:16:9:18:31 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/workflow_run_untrusted_checkout.yml:2:3:2:14 | workflow_run | workflow_run |
2223
| .github/workflows/workflow_run_untrusted_checkout_2.yml:13:9:16:6 | Uses Step | Checkout of untrusted code in a privileged workflow with later potential execution (event trigger: $@). | .github/workflows/workflow_run_untrusted_checkout_2.yml:2:3:2:14 | workflow_run | workflow_run |

0 commit comments

Comments
 (0)