diff --git a/ql/lib/codeql/actions/dataflow/FlowSources.qll b/ql/lib/codeql/actions/dataflow/FlowSources.qll index c0e0e759120..e07b9f76762 100644 --- a/ql/lib/codeql/actions/dataflow/FlowSources.qll +++ b/ql/lib/codeql/actions/dataflow/FlowSources.qll @@ -22,6 +22,13 @@ abstract class RemoteFlowSource extends SourceNode { override string getThreatModel() { result = "remote" } } +bindingset[context] +private predicate isExternalUserControlled(string context) { + exists(string reg | reg = "github\\.event" | + Utils::normalizeExpr(context).regexpMatch(Utils::wrapRegexp(reg)) + ) +} + bindingset[context] private predicate isExternalUserControlledIssue(string context) { exists(string reg | reg = ["github\\.event\\.issue\\.title", "github\\.event\\.issue\\.body"] | @@ -123,6 +130,7 @@ private predicate isExternalUserControlledWorkflowRun(string context) { private class EventSource extends RemoteFlowSource { EventSource() { exists(Expression e, string context | this.asExpr() = e and context = e.getExpression() | + isExternalUserControlled(context) or isExternalUserControlledIssue(context) or isExternalUserControlledPullRequest(context) or isExternalUserControlledReview(context) or diff --git a/ql/test/query-tests/Security/CWE-094/.github/workflows/simple3.yml b/ql/test/query-tests/Security/CWE-094/.github/workflows/simple3.yml new file mode 100644 index 00000000000..be1559d4711 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-094/.github/workflows/simple3.yml @@ -0,0 +1,23 @@ +on: + workflow_run: + workflows: + - 'prev' + types: + - completed + +permissions: + actions: read + checks: read + contents: read + +jobs: + echo_trigger: + name: Report changes + runs-on: ubuntu-latest + steps: + - name: Echo trigger + run: | + echo "head branch: ${{ github.event.workflow_run.head_branch }}" + cat << EOF + ${{ toJSON(github.event) }} + EOF diff --git a/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/ql/test/query-tests/Security/CWE-094/CodeInjection.expected index 1a12b8e7277..a300f4dd11e 100644 --- a/ql/test/query-tests/Security/CWE-094/CodeInjection.expected +++ b/ql/test/query-tests/Security/CWE-094/CodeInjection.expected @@ -200,6 +200,8 @@ nodes | .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] | semmle.label | Uses Step: step [value] | | .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files | semmle.label | steps.source.outputs.all_changed_files | | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | semmle.label | steps.step.outputs.value | +| .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | semmle.label | toJSON(github.event) | | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY | semmle.label | env.ISSUE_KEY | diff --git a/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected b/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected index f4df15ae344..f025d13b1a9 100644 --- a/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected +++ b/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected @@ -200,6 +200,8 @@ nodes | .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] | semmle.label | Uses Step: step [value] | | .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files | semmle.label | steps.source.outputs.all_changed_files | | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | semmle.label | steps.step.outputs.value | +| .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | semmle.label | toJSON(github.event) | | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY | semmle.label | env.ISSUE_KEY | @@ -307,6 +309,8 @@ subpaths | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | .github/workflows/self_needs.yml:16:20:16:64 | github.event['head_commit']['message'] | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/self_needs.yml:20:15:20:51 | needs.test1.outputs.job_output | ${{ needs.test1.outputs.job_output }} | | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | .github/workflows/simple1.yml:11:20:11:58 | github.event.head_commit.message | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple1.yml:16:18:16:49 | steps.summary.outputs.value | ${{steps.summary.outputs.value}} | | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | .github/workflows/simple2.yml:14:9:18:6 | Uses Step: source | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value | ${{ steps.step.outputs.value }} | +| .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple3.yml:23:31:23:74 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} | +| .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple3.yml:25:11:25:37 | toJSON(github.event) | ${{ toJSON(github.event) }} | | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | ${{ github.event.pull_request.title }} | | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY | .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY | ${{ env.ISSUE_KEY }} | | .github/workflows/test.yml:49:20:49:56 | needs.job1.outputs['job_output'] | .github/workflows/test.yml:15:20:15:64 | github.event['head_commit']['message'] | .github/workflows/test.yml:49:20:49:56 | needs.job1.outputs['job_output'] | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/test.yml:49:20:49:56 | needs.job1.outputs['job_output'] | ${{needs.job1.outputs['job_output']}} |