From 1b2e02df64938e6edca0b98b0d34f86d094e4ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Thu, 11 Apr 2024 15:18:09 +0200 Subject: [PATCH] Add support for multiline assigments --- ql/lib/codeql/actions/Ast.qll | 66 +++++++++++++++---- ql/lib/codeql/actions/dataflow/FlowSteps.qll | 33 +++++++--- .../security/ArtifactPoisoningQuery.qll | 2 +- .../actions/security/EnvVarInjectionQuery.qll | 58 +++++++++------- .../.github/workflows/multiline.yml | 29 ++++++++ ql/test/library-tests/test.ql | 4 +- .../CWE-077/.github/workflows/test4.yml | 43 ++++++++++++ .../Security/CWE-077/EnvVarInjection.expected | 6 ++ .../PrivilegedEnvVarInjection.expected | 8 +++ .../Security/CWE-094/CodeInjection.expected | 4 +- .../CWE-094/PrivilegedCodeInjection.expected | 8 +-- .../.github/workflows/artifactpoisoning51.yml | 4 -- .../.github/workflows/artifactpoisoning52.yml | 27 ++++++++ .../.github/workflows/artifactpoisoning53.yml | 27 ++++++++ .../CWE-829/ArtifactPoisoning.expected | 2 + 15 files changed, 265 insertions(+), 56 deletions(-) create mode 100644 ql/test/library-tests/.github/workflows/multiline.yml create mode 100644 ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml create mode 100644 ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning52.yml create mode 100644 ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning53.yml diff --git a/ql/lib/codeql/actions/Ast.qll b/ql/lib/codeql/actions/Ast.qll index bbf5c86fb95..cf5b63399f0 100644 --- a/ql/lib/codeql/actions/Ast.qll +++ b/ql/lib/codeql/actions/Ast.qll @@ -25,14 +25,17 @@ module Utils { } bindingset[line, var] - predicate extractAssignment(string line, string var, string key, string value) { + private predicate extractLineAssignment(string line, string var, string key, string value) { exists(string assignment | + // single line assignment assignment = - line.regexpCapture("(echo|Write-Output)\\s+(.*)\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + + line.regexpCapture("(echo|Write-Output)\\s+(.*)>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() + "(\\})?(\"|')?", 2) and + count(assignment.splitAt("=")) = 2 and key = trimQuotes(assignment.splitAt("=", 0)) and value = trimQuotes(assignment.splitAt("=", 1)) or + // workflow command assignment assignment = line.regexpCapture("(echo|Write-Output)\\s+(\"|')?::set-" + var.toLowerCase() + "\\s+name=(.*)(\"|')?", 3).regexpReplaceAll("^\"", "").regexpReplaceAll("\"$", "") and @@ -41,20 +44,59 @@ module Utils { ) } - predicate writeToGitHubEnv(Run run, string key, string value) { - exists(string script, string line | - script = run.getScript() and - line = script.splitAt("\n") and - Utils::extractAssignment(line, "ENV", key, value) + bindingset[var] + private string multilineAssignmentRegex(string var) { + result = + ".*(echo|Write-Output)\\s+(.*)<<\\s*([A-Z]*)EOF(.+)(echo|Write-Output)\\s+(\"|')?([A-Z]*)EOF(\"|')?\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + + var.toUpperCase() + "(\\})?(\"|')?.*" + } + + bindingset[var] + private string multilineBlockAssignmentRegex(string var) { + result = + ".*\\{(\\s|::NEW_LINE::)*(echo|Write-Output)\\s+(.*)<<\\s*([A-Z]*)EOF(.+)(echo|Write-Output)\\s+(\"|')?([A-Z]*)EOF(\"|')?(\\s|::NEW_LINE::)*\\}\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + + var.toUpperCase() + "(\\})?(\"|')?.*" + } + + bindingset[script, var] + private predicate extractMultilineAssignment(string script, string var, string key, string value) { + // multiline assignment + exists(string flattenedScript | + flattenedScript = script.replaceAll("\n", "::NEW_LINE::") and + value = + "$(" + + trimQuotes(flattenedScript.regexpCapture(multilineAssignmentRegex(var), 4)) + .regexpReplaceAll("\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() + + "(\\})?(\"|')?", "") + .replaceAll("::NEW_LINE::", "\n") + .trim() + .splitAt("\n") + ")" and + key = trimQuotes(flattenedScript.regexpCapture(multilineAssignmentRegex(var), 2)) + ) + or + // multiline block assignment + exists(string flattenedScript | + flattenedScript = script.replaceAll("\n", "::NEW_LINE::") and + value = + "$(" + + trimQuotes(flattenedScript.regexpCapture(multilineBlockAssignmentRegex(var), 5)) + .regexpReplaceAll("\\s*>>\\s*(\"|')?\\$(\\{)?GITHUB_" + var.toUpperCase() + + "(\\})?(\"|')?", "") + .replaceAll("::NEW_LINE::", "\n") + .trim() + .splitAt("\n") + ")" and + key = trimQuotes(flattenedScript.regexpCapture(multilineBlockAssignmentRegex(var), 3)) ) } + predicate writeToGitHubEnv(Run run, string key, string value) { + extractLineAssignment(run.getScript().splitAt("\n"), "ENV", key, value) or + extractMultilineAssignment(run.getScript(), "ENV", key, value) + } + predicate writeToGitHubOutput(Run run, string key, string value) { - exists(string script, string line | - script = run.getScript() and - line = script.splitAt("\n") and - Utils::extractAssignment(line, "OUTPUT", key, value) - ) + extractLineAssignment(run.getScript().splitAt("\n"), "OUTPUT", key, value) or + extractMultilineAssignment(run.getScript(), "OUTPUT", key, value) } } diff --git a/ql/lib/codeql/actions/dataflow/FlowSteps.qll b/ql/lib/codeql/actions/dataflow/FlowSteps.qll index e66c8e7c1b9..48c40b6a72c 100644 --- a/ql/lib/codeql/actions/dataflow/FlowSteps.qll +++ b/ql/lib/codeql/actions/dataflow/FlowSteps.qll @@ -36,19 +36,36 @@ class AdditionalTaintStep extends Unit { * echo "foo=$(echo $BODY)" >> "$GITHUB_OUTPUT" */ predicate envToOutputStoreStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c) { - exists(Run run, string varName, string output | - c = any(DataFlow::FieldContent ct | ct.getName() = output.replaceAll("output\\.", "")) and + exists(Run run, string varName, string key, string value | + c = any(DataFlow::FieldContent ct | ct.getName() = key.replaceAll("output\\.", "")) and run.getInScopeEnvVarExpr(varName) = pred.asExpr() and - exists(string script, string line | - script = run.getScript() and - line = script.splitAt("\n") and - Utils::extractAssignment(line, "OUTPUT", output, _) and - line.indexOf("$" + ["", "{", "ENV{"] + varName) > 0 - ) and + Utils::writeToGitHubOutput(run, key, value) and + value.matches("%$" + ["", "{", "ENV{"] + varName + "%") and succ.asExpr() = run ) } +/** + * Holds if a Run step declares an environment variable, uses it in its script to set another env var. + * e.g. + * env: + * BODY: ${{ github.event.comment.body }} + * run: | + * echo "foo=$(echo $BODY)" >> $GITHUB_ENV + */ +predicate envToRunStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(Run run, string varName, string value | + run.getInScopeEnvVarExpr(varName) = pred.asExpr() and + Utils::writeToGitHubEnv(run, _, value) and + value.indexOf("$" + ["", "{", "ENV{"] + varName) > 0 and + succ.asExpr() = run + ) +} + +class EnvToRunTaintStep extends AdditionalTaintStep { + override predicate step(DataFlow::Node node1, DataFlow::Node node2) { envToRunStep(node1, node2) } +} + /** * A downloaded artifact that gets assigned to a Run step output. * - uses: actions/download-artifact@v2 diff --git a/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll b/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll index c192974a12b..4a334f3440f 100644 --- a/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll +++ b/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll @@ -250,7 +250,7 @@ class EnvVarInjectionRunStep extends PoisonableStep, Run { // eg: `echo "sha=$(> $GITHUB_ENV` Utils::writeToGitHubEnv(this, _, value) and // TODO: add support for other commands like `<`, `jq`, ... - value.regexpMatch(["\\$\\(", "`"] + ["cat\\s+", "<"] + ".*" + ["`", "\\)"]) + value.regexpMatch(["\\$\\(", "`"] + ["ls\\s+", "cat\\s+", "<"] + ".*" + ["`", "\\)"]) ) } } diff --git a/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll b/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll index d216707ec86..edeea61a871 100644 --- a/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll +++ b/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll @@ -5,35 +5,47 @@ import codeql.actions.dataflow.FlowSources private import codeql.actions.security.ArtifactPoisoningQuery import codeql.actions.DataFlow -class EnvVarInjectionFromExprSink extends DataFlow::Node { - EnvVarInjectionFromExprSink() { - exists(Expression expr, Run run, string script, string line, string key, string value | - script = run.getScript() and - line = script.splitAt("\n") and - Utils::extractAssignment(line, "ENV", key, value) and - expr = this.asExpr() and - run.getAnScriptExpr() = expr and - value.indexOf(expr.getRawExpression()) > 0 - ) - } +predicate envVarInjectionFromExprSink(DataFlow::Node sink) { + exists(Expression expr, Run run, string key, string value | + Utils::writeToGitHubEnv(run, key, value) and + expr = sink.asExpr() and + run.getAnScriptExpr() = expr and + value.indexOf(expr.getRawExpression()) > 0 + ) } -class EnvVarInjectionFromFileSink extends DataFlow::Node { - EnvVarInjectionFromFileSink() { - exists(Run run, ArtifactDownloadStep step, string value | - this.asExpr() = run and - step.getAFollowingStep() = run and - Utils::writeToGitHubEnv(run, _, value) and - // TODO: add support for other commands like `<`, `jq`, ... - value.regexpMatch(["\\$\\(", "`"] + ["cat\\s+", "<"] + ".*" + ["`", "\\)"]) - ) - } +predicate envVarInjectionFromFileSink(DataFlow::Node sink) { + exists(Run run, ArtifactDownloadStep step, string value | + sink.asExpr() = run and + step.getAFollowingStep() = run and + Utils::writeToGitHubEnv(run, _, value) and + // TODO: add support for other commands like `<`, `jq`, ... + value.regexpMatch(["\\$\\(", "`"] + ["cat\\s+", "<"] + ".*" + ["`", "\\)"]) + ) +} + +/** + * Holds if a Run step declares an environment variable, uses it to declare a new env var. + * e.g. + * env: + * BODY: ${{ github.event.comment.body }} + * run: | + * echo "foo=$(echo $BODY)" >> $GITHUB_ENV + */ +predicate envVarInjectionFromEnvSink(DataFlow::Node sink) { + exists(Run run, Expression expr, string varName, string value | + sink.asExpr().getInScopeEnvVarExpr(varName) = expr and + run = sink.asExpr() and + Utils::writeToGitHubEnv(run, _, value) and + value.indexOf("$" + ["", "{", "ENV{"] + varName) > 0 + ) } private class EnvVarInjectionSink extends DataFlow::Node { EnvVarInjectionSink() { - this instanceof EnvVarInjectionFromExprSink or - this instanceof EnvVarInjectionFromFileSink or + envVarInjectionFromExprSink(this) or + envVarInjectionFromFileSink(this) or + envVarInjectionFromEnvSink(this) or externallyDefinedSink(this, "envvar-injection") } } diff --git a/ql/test/library-tests/.github/workflows/multiline.yml b/ql/test/library-tests/.github/workflows/multiline.yml new file mode 100644 index 00000000000..04468cb15a1 --- /dev/null +++ b/ql/test/library-tests/.github/workflows/multiline.yml @@ -0,0 +1,29 @@ +on: + workflow_run: + workflows: ["Prev"] + types: + - completed + +jobs: + Test: + runs-on: ubuntu-latest + steps: + run: | + echo "changelog<> $GITHUB_OUTPUT + echo -e "$FILTERED_CHANGELOG" >> $GITHUB_OUTPUT + echo "CHANGELOGEOF" >> $GITHUB_OUTPUT + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "status<<$EOF" >> $GITHUB_OUTPUT + echo "$(cat status.output.json)" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + run: | + echo "response<<$EOF" >> $GITHUB_OUTPUT + echo $output >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + - run: | + { + echo 'JSON_RESPONSE<> "$GITHUB_ENV" diff --git a/ql/test/library-tests/test.ql b/ql/test/library-tests/test.ql index 947757c8c3a..fa6c430e366 100644 --- a/ql/test/library-tests/test.ql +++ b/ql/test/library-tests/test.ql @@ -80,7 +80,7 @@ query predicate writeToGitHubEnv(string key, string value) { "echo 'sha2=$(> $GITHUB_ENV", "echo sha3=$(> $GITHUB_ENV", ] and - Utils::extractAssignment(t, "ENV", key, value) + Utils::extractLineAssignment(t, "ENV", key, value) ) } @@ -98,6 +98,6 @@ query predicate writeToGitHubOutput(string key, string value) { "echo sha5=$(> ${GITHUB_OUTPUT}", "echo sha6=$(> \"${GITHUB_OUTPUT}\"", ] and - Utils::extractAssignment(t, "OUTPUT", key, value) + Utils::extractLineAssignment(t, "OUTPUT", key, value) ) } diff --git a/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml b/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml new file mode 100644 index 00000000000..7fb89591b11 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-077/.github/workflows/test4.yml @@ -0,0 +1,43 @@ +name: Pull Request Open + +on: + pull_request_target: + branches: + - main + - 14.0.x + + types: + - opened + - reopened + +jobs: + updateJira: + if: github.actor != 'dependabot[bot]' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - env: + TITLE: ${{ github.event.pull_request.title }} + run: | + echo PR_TITLE=$(echo $TITLE) >> $GITHUB_ENV + - env: + TITLE: ${{ github.event.pull_request.title }} + run: | + echo "PR_TITLE<> $GITHUB_ENV + echo "$TITLE" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + - run: | + echo "PACKAGES_FILE_LIST<> "${GITHUB_ENV}" + ls | grep -E "*.(tar.gz|zip)$" >> "${GITHUB_ENV}" + ls | grep -E "*.(txt|md)$" >> "${GITHUB_ENV}" + echo "EOF" >> "${GITHUB_ENV}" + - run: | + { + echo 'JSON_RESPONSE<> "$GITHUB_ENV" + + diff --git a/ql/test/query-tests/Security/CWE-077/EnvVarInjection.expected b/ql/test/query-tests/Security/CWE-077/EnvVarInjection.expected index 0c4574a77cb..32379a7264f 100644 --- a/ql/test/query-tests/Security/CWE-077/EnvVarInjection.expected +++ b/ql/test/query-tests/Security/CWE-077/EnvVarInjection.expected @@ -3,6 +3,8 @@ edges | .github/workflows/test2.yml:17:9:47:6 | Uses Step | .github/workflows/test2.yml:47:9:52:6 | Run Step | | .github/workflows/test3.yml:17:7:24:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | | .github/workflows/test3.yml:24:7:31:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | +| .github/workflows/test4.yml:22:19:22:56 | github.event.pull_request.title | .github/workflows/test4.yml:21:9:25:6 | Run Step | +| .github/workflows/test4.yml:26:19:26:56 | github.event.pull_request.title | .github/workflows/test4.yml:25:9:31:6 | Run Step | nodes | .github/workflows/sonar-source.yml:17:9:37:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/sonar-source.yml:39:9:45:6 | Run Step | semmle.label | Run Step | @@ -12,5 +14,9 @@ nodes | .github/workflows/test3.yml:17:7:24:4 | Uses Step | semmle.label | Uses Step | | .github/workflows/test3.yml:24:7:31:4 | Uses Step | semmle.label | Uses Step | | .github/workflows/test3.yml:39:7:44:4 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:21:9:25:6 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:22:19:22:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/test4.yml:25:9:31:6 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:26:19:26:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | subpaths #select diff --git a/ql/test/query-tests/Security/CWE-077/PrivilegedEnvVarInjection.expected b/ql/test/query-tests/Security/CWE-077/PrivilegedEnvVarInjection.expected index 6dbe7bf3c93..77db4c10344 100644 --- a/ql/test/query-tests/Security/CWE-077/PrivilegedEnvVarInjection.expected +++ b/ql/test/query-tests/Security/CWE-077/PrivilegedEnvVarInjection.expected @@ -3,6 +3,8 @@ edges | .github/workflows/test2.yml:17:9:47:6 | Uses Step | .github/workflows/test2.yml:47:9:52:6 | Run Step | | .github/workflows/test3.yml:17:7:24:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | | .github/workflows/test3.yml:24:7:31:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | +| .github/workflows/test4.yml:22:19:22:56 | github.event.pull_request.title | .github/workflows/test4.yml:21:9:25:6 | Run Step | +| .github/workflows/test4.yml:26:19:26:56 | github.event.pull_request.title | .github/workflows/test4.yml:25:9:31:6 | Run Step | nodes | .github/workflows/sonar-source.yml:17:9:37:6 | Uses Step | semmle.label | Uses Step | | .github/workflows/sonar-source.yml:39:9:45:6 | Run Step | semmle.label | Run Step | @@ -12,6 +14,10 @@ nodes | .github/workflows/test3.yml:17:7:24:4 | Uses Step | semmle.label | Uses Step | | .github/workflows/test3.yml:24:7:31:4 | Uses Step | semmle.label | Uses Step | | .github/workflows/test3.yml:39:7:44:4 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:21:9:25:6 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:22:19:22:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | +| .github/workflows/test4.yml:25:9:31:6 | Run Step | semmle.label | Run Step | +| .github/workflows/test4.yml:26:19:26:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title | subpaths #select | .github/workflows/sonar-source.yml:39:9:45:6 | Run Step | .github/workflows/sonar-source.yml:17:9:37:6 | Uses Step | .github/workflows/sonar-source.yml:39:9:45:6 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/sonar-source.yml:39:9:45:6 | Run Step | Run Step | @@ -19,3 +25,5 @@ subpaths | .github/workflows/test2.yml:47:9:52:6 | Run Step | .github/workflows/test2.yml:17:9:47:6 | Uses Step | .github/workflows/test2.yml:47:9:52:6 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test2.yml:47:9:52:6 | Run Step | Run Step | | .github/workflows/test3.yml:39:7:44:4 | Run Step | .github/workflows/test3.yml:17:7:24:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test3.yml:39:7:44:4 | Run Step | Run Step | | .github/workflows/test3.yml:39:7:44:4 | Run Step | .github/workflows/test3.yml:24:7:31:4 | Uses Step | .github/workflows/test3.yml:39:7:44:4 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test3.yml:39:7:44:4 | Run Step | Run Step | +| .github/workflows/test4.yml:21:9:25:6 | Run Step | .github/workflows/test4.yml:22:19:22:56 | github.event.pull_request.title | .github/workflows/test4.yml:21:9:25:6 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test4.yml:21:9:25:6 | Run Step | Run Step | +| .github/workflows/test4.yml:25:9:31:6 | Run Step | .github/workflows/test4.yml:26:19:26:56 | github.event.pull_request.title | .github/workflows/test4.yml:25:9:31:6 | Run Step | Potential privileged environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test4.yml:25:9:31:6 | Run Step | Run Step | diff --git a/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/ql/test/query-tests/Security/CWE-094/CodeInjection.expected index a300f4dd11e..bf515674d90 100644 --- a/ql/test/query-tests/Security/CWE-094/CodeInjection.expected +++ b/ql/test/query-tests/Security/CWE-094/CodeInjection.expected @@ -200,8 +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/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/simple3.yml:22:11:22: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 f025d13b1a9..6ba7a1c714a 100644 --- a/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected +++ b/ql/test/query-tests/Security/CWE-094/PrivilegedCodeInjection.expected @@ -200,8 +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/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch | +| .github/workflows/simple3.yml:22:11:22: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 | @@ -309,8 +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/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | .github/workflows/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | .github/workflows/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple3.yml:20:31:20:74 | github.event.workflow_run.head_branch | ${{ github.event.workflow_run.head_branch }} | +| .github/workflows/simple3.yml:22:11:22:37 | toJSON(github.event) | .github/workflows/simple3.yml:22:11:22:37 | toJSON(github.event) | .github/workflows/simple3.yml:22:11:22:37 | toJSON(github.event) | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/simple3.yml:22:11:22: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']}} | diff --git a/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning51.yml b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning51.yml index ca074428ccf..71f590fbc9c 100644 --- a/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning51.yml +++ b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning51.yml @@ -18,7 +18,3 @@ jobs: - name: Env Var Injection run: | echo "pr_number=$(cat foo/bar)" >> $GITHUB_ENV - - - - diff --git a/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning52.yml b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning52.yml new file mode 100644 index 00000000000..130668b8515 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning52.yml @@ -0,0 +1,27 @@ +name: Pull Request Open + +on: + workflow_run: + workflows: ["Prev"] + types: + - completed + +jobs: + Download: + runs-on: ubuntu-latest + steps: + - run: | + gh run download "${{github.event.workflow_run.id}}" --repo "${GITHUB_REPOSITORY}" --name "artifact_name" + - name: Unzip + run: | + unzip artifact_name.zip -d foo + - name: Env Var Injection + run: | + echo "PACKAGES_FILE_LIST<> "${GITHUB_ENV}" + ls | grep -E "*.(tar.gz|zip)$" >> "${GITHUB_ENV}" + ls | grep -E "*.(txt|md)$" >> "${GITHUB_ENV}" + echo "EOF" >> "${GITHUB_ENV}" + + + + diff --git a/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning53.yml b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning53.yml new file mode 100644 index 00000000000..7c255e7722d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning53.yml @@ -0,0 +1,27 @@ +name: Pull Request Open + +on: + workflow_run: + workflows: ["Prev"] + types: + - completed + +jobs: + Download: + runs-on: ubuntu-latest + steps: + - run: | + gh run download "${{github.event.workflow_run.id}}" --repo "${GITHUB_REPOSITORY}" --name "artifact_name" + - name: Unzip + run: | + unzip artifact_name.zip -d foo + - run: | + { + echo 'JSON_RESPONSE<> "$GITHUB_ENV" + + + + diff --git a/ql/test/query-tests/Security/CWE-829/ArtifactPoisoning.expected b/ql/test/query-tests/Security/CWE-829/ArtifactPoisoning.expected index 907979b88e7..ab07d0a2f38 100644 --- a/ql/test/query-tests/Security/CWE-829/ArtifactPoisoning.expected +++ b/ql/test/query-tests/Security/CWE-829/ArtifactPoisoning.expected @@ -8,3 +8,5 @@ | .github/workflows/artifactpoisoning41.yml:13:9:21:6 | Run Step | Potential artifact poisoning. | | .github/workflows/artifactpoisoning42.yml:13:9:21:6 | Run Step | Potential artifact poisoning. | | .github/workflows/artifactpoisoning51.yml:13:9:15:6 | Run Step | Potential artifact poisoning. | +| .github/workflows/artifactpoisoning52.yml:13:9:15:6 | Run Step | Potential artifact poisoning. | +| .github/workflows/artifactpoisoning53.yml:13:9:15:6 | Run Step | Potential artifact poisoning. |