Skip to content

Commit 5cd292e

Browse files
author
Alvaro Muñoz
committed
Make Untrusted Checkout and CachePoisoning rules path-problems
1 parent e631196 commit 5cd292e

File tree

7 files changed

+451
-27
lines changed

7 files changed

+451
-27
lines changed

ql/src/Security/CWE-349/CachePoisoning.ql

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Cache Poisoning
33
* @description The cache can be poisoned by untrusted code, leading to a cache poisoning attack.
4-
* @kind problem
4+
* @kind path-problem
55
* @problem.severity error
66
* @precision high
77
* @security-severity 7.5
@@ -16,6 +16,8 @@ import codeql.actions.security.UntrustedCheckoutQuery
1616
import codeql.actions.security.CachePoisoningQuery
1717
import codeql.actions.security.PoisonableSteps
1818

19+
query predicate edges(Step a, Step b) { a.getAFollowingStep() = b }
20+
1921
from LocalJob j, Event e, PRHeadCheckoutStep checkout, Step s
2022
where
2123
j.getATriggerEvent() = e and
@@ -48,5 +50,4 @@ where
4850
// excluding privileged workflows since they can be exploited in easier circumstances
4951
not j.isPrivileged()
5052
)
51-
select checkout, "Potential cache poisoning in the context of the default branch on step $@.", s,
52-
s.toString()
53+
select s, checkout, s, "Potential cache poisoning in the context of the default branch"

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @description Priveleged workflows have read/write access to the base repository and access to secrets.
44
* By explicitly checking out and running the build script from a fork the untrusted code is running in an environment
55
* that is able to push to the base repository and to access secrets.
6-
* @kind problem
6+
* @kind path-problem
77
* @problem.severity error
88
* @precision very-high
99
* @security-severity 9.3
@@ -17,12 +17,14 @@ import actions
1717
import codeql.actions.security.UntrustedCheckoutQuery
1818
import codeql.actions.security.PoisonableSteps
1919

20-
from LocalJob j, PRHeadCheckoutStep checkout
20+
query predicate edges(Step a, Step b) { a.getAFollowingStep() = b }
21+
22+
from LocalJob j, PRHeadCheckoutStep checkout, PoisonableStep s
2123
where
2224
j = checkout.getEnclosingJob() and
2325
j.getAStep() = checkout and
2426
// the checkout is followed by a known poisonable step
25-
checkout.getAFollowingStep() instanceof PoisonableStep and
27+
checkout.getAFollowingStep() = s and
2628
// the checkout is not controlled by an access check
2729
not exists(ControlCheck check | check.dominates(checkout)) and
2830
// the checkout occurs in a privileged context
@@ -31,4 +33,4 @@ where
3133
or
3234
inPrivilegedExternallyTriggerableJob(checkout)
3335
)
34-
select checkout, "Potential unsafe checkout of untrusted pull request on privileged workflow."
36+
select s, checkout, s, "Potential unsafe checkout of untrusted code on a privileged workflow."
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
run-name: Cleanup ${{ github.head_ref }}
2+
on:
3+
pull_request_target:
4+
types: labeled
5+
paths:
6+
- 'images/**'
7+
8+
jobs:
9+
clean_ci:
10+
name: Clean CI runs
11+
runs-on: ubuntu-latest
12+
permissions:
13+
actions: write
14+
steps:
15+
- env:
16+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17+
shell: pwsh
18+
run: |
19+
$startDate = Get-Date -UFormat %s
20+
$workflows = @("macos11", "macos12", "ubuntu2004", "ubuntu2204", "windows2019", "windows2022")
21+
while ($true) {
22+
$continue = $false
23+
foreach ($wf in $workflows) {
24+
$skippedCommand = "gh run list --workflow ${wf}.yml --branch ${{ github.event.pull_request.head.ref }} --repo ${{ github.repository }} --status skipped --json databaseId"
25+
$skippedIds = Invoke-Expression -Command $skippedCommand | ConvertFrom-Json | ForEach-Object { $_.databaseId }
26+
$skippedIds | ForEach-Object {
27+
$deleteCommand = "gh run delete --repo ${{ github.repository }} $_"
28+
Invoke-Expression -Command $deleteCommand
29+
}
30+
$pendingCommand = "gh run list --workflow ${wf}.yml --branch ${{ github.event.pull_request.head.ref }} --repo ${{ github.repository }} --status requested --json databaseId --template '{{ . | len }}'"
31+
$pending = Invoke-Expression -Command $pendingCommand
32+
if ($pending -gt 0) {
33+
Write-Host "Pending for ${wf}.yml: $pending run(s)"
34+
$continue = $true
35+
}
36+
}
37+
if ($continue -eq $false) {
38+
Write-Host "All done, exiting"
39+
break
40+
}
41+
$curDate = Get-Date -UFormat %s
42+
if (($curDate - $startDate) -gt 60) {
43+
Write-Host "Reached timeout, exiting"
44+
break
45+
}
46+
Write-Host "Waiting 5 seconds..."
47+
Start-Sleep -Seconds 5
48+
}

ql/test/query-tests/Security/CWE-094/CodeInjectionCritical.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ nodes
249249
| .github/workflows/test7.yml:13:9:17:6 | Uses Step: refs | semmle.label | Uses Step: refs |
250250
| .github/workflows/test7.yml:18:37:18:80 | steps.comment-branch.outputs.head_ref | semmle.label | steps.comment-branch.outputs.head_ref |
251251
| .github/workflows/test7.yml:20:37:20:70 | steps.refs.outputs.head_ref | semmle.label | steps.refs.outputs.head_ref |
252+
| .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
253+
| .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
252254
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] |
253255
| .github/workflows/test.yml:8:20:8:50 | steps.step5.outputs.MSG5 | semmle.label | steps.step5.outputs.MSG5 |
254256
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | semmle.label | Uses Step: step0 [value] |
@@ -348,6 +350,8 @@ subpaths
348350
| .github/workflows/test5.yml:12:21:12:64 | toJSON(github.event.comment.body).foo | .github/workflows/test5.yml:12:21:12:64 | toJSON(github.event.comment.body).foo | .github/workflows/test5.yml:12:21:12:64 | toJSON(github.event.comment.body).foo | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test5.yml:12:21:12:64 | toJSON(github.event.comment.body).foo | ${{ toJSON(github.event.comment.body).foo }} |
349351
| .github/workflows/test7.yml:18:37:18:80 | steps.comment-branch.outputs.head_ref | .github/workflows/test7.yml:9:9:13:6 | Uses Step: comment-branch | .github/workflows/test7.yml:18:37:18:80 | steps.comment-branch.outputs.head_ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test7.yml:18:37:18:80 | steps.comment-branch.outputs.head_ref | ${{ steps.comment-branch.outputs.head_ref }} |
350352
| .github/workflows/test7.yml:20:37:20:70 | steps.refs.outputs.head_ref | .github/workflows/test7.yml:13:9:17:6 | Uses Step: refs | .github/workflows/test7.yml:20:37:20:70 | steps.refs.outputs.head_ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test7.yml:20:37:20:70 | steps.refs.outputs.head_ref | ${{ steps.refs.outputs.head_ref }} |
353+
| .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | ${{ github.event.pull_request.head.ref }} |
354+
| .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | ${{ github.event.pull_request.head.ref }} |
351355
| .github/workflows/workflow_run.yml:9:19:9:64 | github.event.workflow_run.display_title | .github/workflows/workflow_run.yml:9:19:9:64 | github.event.workflow_run.display_title | .github/workflows/workflow_run.yml:9:19:9:64 | github.event.workflow_run.display_title | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run.yml:9:19:9:64 | github.event.workflow_run.display_title | ${{ github.event.workflow_run.display_title }} |
352356
| .github/workflows/workflow_run.yml:10:19:10:70 | github.event.workflow_run.head_commit.message | .github/workflows/workflow_run.yml:10:19:10:70 | github.event.workflow_run.head_commit.message | .github/workflows/workflow_run.yml:10:19:10:70 | github.event.workflow_run.head_commit.message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run.yml:10:19:10:70 | github.event.workflow_run.head_commit.message | ${{ github.event.workflow_run.head_commit.message }} |
353357
| .github/workflows/workflow_run.yml:11:19:11:75 | github.event.workflow_run.head_commit.author.email | .github/workflows/workflow_run.yml:11:19:11:75 | github.event.workflow_run.head_commit.author.email | .github/workflows/workflow_run.yml:11:19:11:75 | github.event.workflow_run.head_commit.author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/workflow_run.yml:11:19:11:75 | github.event.workflow_run.head_commit.author.email | ${{ github.event.workflow_run.head_commit.author.email }} |

ql/test/query-tests/Security/CWE-094/CodeInjectionMedium.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ nodes
249249
| .github/workflows/test7.yml:13:9:17:6 | Uses Step: refs | semmle.label | Uses Step: refs |
250250
| .github/workflows/test7.yml:18:37:18:80 | steps.comment-branch.outputs.head_ref | semmle.label | steps.comment-branch.outputs.head_ref |
251251
| .github/workflows/test7.yml:20:37:20:70 | steps.refs.outputs.head_ref | semmle.label | steps.refs.outputs.head_ref |
252+
| .github/workflows/test8.yml:24:76:24:116 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
253+
| .github/workflows/test8.yml:30:76:30:116 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
252254
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] |
253255
| .github/workflows/test.yml:8:20:8:50 | steps.step5.outputs.MSG5 | semmle.label | steps.step5.outputs.MSG5 |
254256
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | semmle.label | Uses Step: step0 [value] |

0 commit comments

Comments
 (0)