Skip to content

Commit 9a7e33b

Browse files
author
Alvaro Muñoz
authored
Merge pull request #103 from github/new_events
Add workflow_dispatch and scheduled to the list of privileged and external (user interaction) events
2 parents 6dbbfa9 + da10ee7 commit 9a7e33b

18 files changed

Lines changed: 195 additions & 139 deletions

ql/lib/codeql/actions/dataflow/FlowSources.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ class GitHubCtxSource extends RemoteFlowSource {
4040

4141
class GitHubEventCtxSource extends RemoteFlowSource {
4242
string flag;
43+
string context;
4344

4445
GitHubEventCtxSource() {
45-
exists(Expression e, string context, string regexp |
46+
exists(Expression e, string regexp |
4647
this.asExpr() = e and
4748
context = e.getExpression() and
4849
(
@@ -62,6 +63,8 @@ class GitHubEventCtxSource extends RemoteFlowSource {
6263
}
6364

6465
override string getSourceType() { result = flag }
66+
67+
string getContext() { result = context }
6568
}
6669

6770
abstract class CommandSource extends RemoteFlowSource {

ql/lib/codeql/actions/security/UntrustedCheckoutQuery.qll

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,23 @@ class ActionsMutableRefCheckout extends MutableRefCheckoutStep instanceof UsesSt
197197
ActionsMutableRefCheckout() {
198198
this.getCallee() = "actions/checkout" and
199199
(
200-
exists(ActionsMutableRefCheckoutFlow::PathNode sink |
201-
ActionsMutableRefCheckoutFlow::flowPath(_, sink) and
202-
sink.getNode().asExpr() = this.getArgumentExpr(["ref", "repository"])
200+
exists(
201+
ActionsMutableRefCheckoutFlow::PathNode source, ActionsMutableRefCheckoutFlow::PathNode sink
202+
|
203+
ActionsMutableRefCheckoutFlow::flowPath(source, sink) and
204+
sink.getNode().asExpr() = this.getArgumentExpr(["ref", "repository"]) and
205+
(
206+
not source.getNode() instanceof GitHubEventCtxSource
207+
or
208+
source.getNode() instanceof GitHubEventCtxSource and
209+
// the context is available for the job trigger events
210+
exists(string context, string context_prefix |
211+
contextTriggerDataModel(this.getEnclosingWorkflow().getATriggerEvent().getName(),
212+
context_prefix) and
213+
context = source.getNode().(GitHubEventCtxSource).getContext() and
214+
normalizeExpr(context).matches("%" + context_prefix + "%")
215+
)
216+
)
203217
)
204218
or
205219
// heuristic base on the step id and field name
@@ -241,9 +255,21 @@ class ActionsSHACheckout extends SHACheckoutStep instanceof UsesStep {
241255
ActionsSHACheckout() {
242256
this.getCallee() = "actions/checkout" and
243257
(
244-
exists(ActionsSHACheckoutFlow::PathNode sink |
245-
ActionsSHACheckoutFlow::flowPath(_, sink) and
246-
sink.getNode().asExpr() = this.getArgumentExpr(["ref", "repository"])
258+
exists(ActionsSHACheckoutFlow::PathNode source, ActionsSHACheckoutFlow::PathNode sink |
259+
ActionsSHACheckoutFlow::flowPath(source, sink) and
260+
sink.getNode().asExpr() = this.getArgumentExpr(["ref", "repository"]) and
261+
(
262+
not source.getNode() instanceof GitHubEventCtxSource
263+
or
264+
source.getNode() instanceof GitHubEventCtxSource and
265+
// the context is available for the job trigger events
266+
exists(string context, string context_prefix |
267+
contextTriggerDataModel(this.getEnclosingWorkflow().getATriggerEvent().getName(),
268+
context_prefix) and
269+
context = source.getNode().(GitHubEventCtxSource).getContext() and
270+
normalizeExpr(context).matches("%" + context_prefix + "%")
271+
)
272+
)
247273
)
248274
or
249275
// heuristic base on the step id and field name

ql/lib/ext/config/context_event_map.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ extensions:
4040
- ["push", "github.event.commits"]
4141
- ["push", "github.event.head_commit"]
4242
- ["push", "github.event.changes"]
43-
- ["repository_dispatch", "github.event.client_payload"]
44-
- ["workflow_dispatch", "github.event.inputs"]
4543
- ["workflow_run", "github.event.workflow"]
4644
- ["workflow_run", "github.event.workflow_run"]
4745
- ["workflow_run", "github.event.changes"]

ql/lib/ext/config/externally_triggereable_events.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ extensions:
1616
- ["pull_request_target"]
1717
- ["workflow_run"] # depending on branch filter
1818
- ["workflow_call"] # depending on caller
19-
19+
- ["workflow_dispatch"]
20+
- ["scheduled"]

ql/lib/ext/config/untrusted_event_properties.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ extensions:
2424
- ["github\\.event\\.workflow_run\\.head_commit\\.message", "text"]
2525
- ["github\\.event\\.pull_request\\.head\\.repo\\.description", "text"]
2626
- ["github\\.event\\.workflow_run\\.head_repository\\.description", "text"]
27-
- ["github\\.event\\.client_payload\\[[0-9]+\\]", "text"]
28-
- ["github\\.event\\.client_payload", "text"]
2927
- ["github\\.event\\.changes\\.body\\.from", "title"]
3028
# BRANCH
3129
- ["github\\.event\\.pull_request\\.head\\.repo\\.default_branch", "branch"]
@@ -59,7 +57,6 @@ extensions:
5957
# JSON
6058
- ["github", "json"]
6159
- ["github\\.event", "json"]
62-
- ["github\\.event\\.client_payload", "json"]
6360
- ["github\\.event\\.comment", "json"]
6461
- ["github\\.event\\.commits", "json"]
6562
- ["github\\.event\\.discussion", "json"]

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ where
4747
) and
4848
// the checkout occurs in a privileged context
4949
inPrivilegedContext(poisonable, event) and
50+
not exists(ControlCheck check | check.protects(checkout, event, "untrusted-checkout")) and
5051
not exists(ControlCheck check | check.protects(poisonable, event, "untrusted-checkout"))
51-
select poisonable, checkout, poisonable, "Execution of untrusted code on a privileged workflow. $@",
52-
event, event.getLocation().getFile().toString()
52+
select poisonable, checkout, poisonable,
53+
"Execution of untrusted code on a privileged workflow ($@)", event,
54+
event.getLocation().getFile().toString()
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
edges
2-
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | provenance | |
3-
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
4-
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
52
nodes
6-
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | semmle.label | input subcommand |
7-
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | semmle.label | inputs.subcommand |
83
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body |
9-
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
10-
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
114
subpaths
125
#select
136
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | Potential command injection in $@, which may be controlled by an external user. | .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | ${{ github.event.comment.body }} |
Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
edges
2-
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | provenance | |
3-
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
4-
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | provenance | |
52
nodes
6-
| .github/actions/run-airbyte-ci/action.yaml:4:3:4:12 | input subcommand | semmle.label | input subcommand |
7-
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | semmle.label | inputs.subcommand |
83
| .github/workflows/comment_issue.yml:9:26:9:57 | github.event.comment.body | semmle.label | github.event.comment.body |
9-
| .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
10-
| .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | semmle.label | github.event.client_payload.connector_name |
114
subpaths
125
#select
13-
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | .github/workflows/test1.yml:46:42:46:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | Potential command injection in $@, which may be controlled by an external user. | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | ${{ inputs.subcommand }} |
14-
| .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | .github/workflows/test1.yml:63:42:63:90 | github.event.client_payload.connector_name | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | Potential command injection in $@, which may be controlled by an external user. | .github/actions/run-airbyte-ci/action.yaml:163:118:163:141 | inputs.subcommand | ${{ inputs.subcommand }} |
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
on:
2+
workflow_dispatch:
3+
4+
jobs:
5+
fetch-issues:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- name: Fetch open issues
9+
id: issues
10+
uses: octokit/request-action@v2.x
11+
with:
12+
route: GET /repos/foo/bar/issues?state=open
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.GITHUBACTIONS_TOKEN }}
15+
16+
- name: Write issues to file
17+
run: |
18+
echo '${{ steps.issues.outputs.data }}' > issues.json
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v2
22+
with:
23+
node-version: '14'
24+
25+
- name: Print issue URLs
26+
run: |
27+
const fs = require('fs');
28+
const issues = JSON.parse(fs.readFileSync('issues.json', 'utf8'));
29+
const filteredIssues = issues.filter(issue => issue.body.includes('Is your portal managed or self-hosted?\r\n\r\nManaged'));
30+
for (const issue of filteredIssues) {
31+
console.log(issue.html_url);
32+
}
33+
shell: bash

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ edges
159159
| .github/workflows/test17.yml:30:13:39:10 | Uses Step: get-pr-details | .github/workflows/test17.yml:45:30:45:88 | fromJson(steps.get-pr-details.outputs.data).head.ref | provenance | |
160160
| .github/workflows/test17.yml:49:13:55:10 | Uses Step: issues | .github/workflows/test17.yml:56:22:56:53 | steps.issues.outputs.data | provenance | |
161161
| .github/workflows/test17.yml:60:13:68:10 | Uses Step: get-pull-request | .github/workflows/test17.yml:69:13:71:55 | fromJson(steps.get-pull-request.outputs.data).title | provenance | |
162+
| .github/workflows/test18.yml:8:9:16:6 | Uses Step: issues | .github/workflows/test18.yml:18:18:18:49 | steps.issues.outputs.data | provenance | |
162163
| .github/workflows/test.yml:11:7:13:4 | Job outputs node [job_output] | .github/workflows/test.yml:52:20:52:56 | needs.job1.outputs['job_output'] | provenance | |
163164
| .github/workflows/test.yml:11:20:11:50 | steps.step5.outputs.MSG5 | .github/workflows/test.yml:11:7:13:4 | Job outputs node [job_output] | provenance | |
164165
| .github/workflows/test.yml:17:9:23:6 | Uses Step: step0 [value] | .github/workflows/test.yml:25:18:25:48 | steps.step0.outputs.value | provenance | |
@@ -484,6 +485,8 @@ nodes
484485
| .github/workflows/test17.yml:56:22:56:53 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data |
485486
| .github/workflows/test17.yml:60:13:68:10 | Uses Step: get-pull-request | semmle.label | Uses Step: get-pull-request |
486487
| .github/workflows/test17.yml:69:13:71:55 | fromJson(steps.get-pull-request.outputs.data).title | semmle.label | fromJson(steps.get-pull-request.outputs.data).title |
488+
| .github/workflows/test18.yml:8:9:16:6 | Uses Step: issues | semmle.label | Uses Step: issues |
489+
| .github/workflows/test18.yml:18:18:18:49 | steps.issues.outputs.data | semmle.label | steps.issues.outputs.data |
487490
| .github/workflows/test.yml:11:7:13:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] |
488491
| .github/workflows/test.yml:11:20:11:50 | steps.step5.outputs.MSG5 | semmle.label | steps.step5.outputs.MSG5 |
489492
| .github/workflows/test.yml:17:9:23:6 | Uses Step: step0 [value] | semmle.label | Uses Step: step0 [value] |
@@ -639,6 +642,7 @@ subpaths
639642
| .github/workflows/test17.yml:45:30:45:88 | fromJson(steps.get-pr-details.outputs.data).head.ref | .github/workflows/test17.yml:30:13:39:10 | Uses Step: get-pr-details | .github/workflows/test17.yml:45:30:45:88 | fromJson(steps.get-pr-details.outputs.data).head.ref | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test17.yml:45:30:45:88 | fromJson(steps.get-pr-details.outputs.data).head.ref | ${{ fromJson(steps.get-pr-details.outputs.data).head.ref }} |
640643
| .github/workflows/test17.yml:56:22:56:53 | steps.issues.outputs.data | .github/workflows/test17.yml:49:13:55:10 | Uses Step: issues | .github/workflows/test17.yml:56:22:56:53 | steps.issues.outputs.data | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test17.yml:56:22:56:53 | steps.issues.outputs.data | ${{ steps.issues.outputs.data }} |
641644
| .github/workflows/test17.yml:69:13:71:55 | fromJson(steps.get-pull-request.outputs.data).title | .github/workflows/test17.yml:60:13:68:10 | Uses Step: get-pull-request | .github/workflows/test17.yml:69:13:71:55 | fromJson(steps.get-pull-request.outputs.data).title | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test17.yml:69:13:71:55 | fromJson(steps.get-pull-request.outputs.data).title | ${{ fromJson(steps.get-pull-request.outputs.data).title }} |
645+
| .github/workflows/test18.yml:18:18:18:49 | steps.issues.outputs.data | .github/workflows/test18.yml:8:9:16:6 | Uses Step: issues | .github/workflows/test18.yml:18:18:18:49 | steps.issues.outputs.data | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test18.yml:18:18:18:49 | steps.issues.outputs.data | ${{ steps.issues.outputs.data }} |
642646
| .github/workflows/test.yml:52:20:52:56 | needs.job1.outputs['job_output'] | .github/workflows/test.yml:20:20:20:62 | github.event['pull_request']['body'] | .github/workflows/test.yml:52:20:52:56 | needs.job1.outputs['job_output'] | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test.yml:52:20:52:56 | needs.job1.outputs['job_output'] | ${{needs.job1.outputs['job_output']}} |
643647
| .github/workflows/untrusted_checkout1.yml:15:20:15:58 | steps.artifact.outputs.pr_number | .github/workflows/untrusted_checkout1.yml:8:9:11:6 | Uses Step | .github/workflows/untrusted_checkout1.yml:15:20:15:58 | steps.artifact.outputs.pr_number | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/untrusted_checkout1.yml:15:20:15:58 | steps.artifact.outputs.pr_number | ${{ steps.artifact.outputs.pr_number }} |
644648
| .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 }} |

0 commit comments

Comments
 (0)