feat(bash): Add support for cat hazelcast/.github/java-config.env >> $GITHUB_ENV

This commit is contained in:
Alvaro Muñoz
2024-08-02 15:48:57 +02:00
parent 90efdc7deb
commit 8cf1a6afa7
7 changed files with 158 additions and 54 deletions

View File

@@ -212,6 +212,32 @@ predicate writeToGitHubPath(Run run, string content) {
extractFileWrite(run.getScript(), "GITHUB_PATH", content)
}
/** Writes the content of the file specified by `path` into a file pointed to by `file_var` */
bindingset[script, file_var]
predicate fileToFileWrite(string script, string file_var, string path) {
exists(string regexp, string line, string file_expr |
isBashParameterExpansion(file_expr, file_var, _, _) and
regexp =
"(?i)(cat)\\s*" + "((?:(?!<<|<<-)[^>\n])+)\\s*" +
"(>>|>|\\s*\\|\\s*tee\\s*(-a|--append)?)\\s*" + "(\\S+)" and
line = script.splitAt("\n") and
path = line.regexpCapture(regexp, 2) and
file_expr = trimQuotes(line.regexpCapture(regexp, 5))
)
}
predicate fileToGitHubEnv(Run run, string path) {
fileToFileWrite(run.getScript(), "GITHUB_ENV", path)
}
predicate fileToGitHubOutput(Run run, string path) {
fileToFileWrite(run.getScript(), "GITHUB_OUTPUT", path)
}
predicate fileToGitHubPath(Run run, string path) {
fileToFileWrite(run.getScript(), "GITHUB_PATH", path)
}
predicate inPrivilegedCompositeAction(AstNode node) {
exists(CompositeAction a |
a = node.getEnclosingCompositeAction() and

View File

@@ -2,6 +2,7 @@ private import actions
private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
private import codeql.actions.security.ArtifactPoisoningQuery
private import codeql.actions.security.UntrustedCheckoutQuery
private import codeql.actions.dataflow.FlowSteps
import codeql.actions.DataFlow
import codeql.actions.dataflow.FlowSources
@@ -16,27 +17,39 @@ abstract class EnvPathInjectionSink extends DataFlow::Node { }
*/
class EnvPathInjectionFromFileReadSink extends EnvPathInjectionSink {
EnvPathInjectionFromFileReadSink() {
exists(Run run, UntrustedArtifactDownloadStep step, string value |
exists(Run run, Step step |
(
step instanceof UntrustedArtifactDownloadStep or
step instanceof PRHeadCheckoutStep
) and
this.asExpr() = run.getScriptScalar() and
step.getAFollowingStep() = run and
writeToGitHubPath(run, value) and
(
outputsPartialFileContent(value)
or
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_PATH
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
// cat test-results/.env >> $GITHUB_PATH
fileToGitHubPath(run, _)
or
exists(string value |
writeToGitHubPath(run, value) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
outputsPartialFileContent(value)
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_PATH
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
)
)
)
)
)

View File

@@ -2,6 +2,7 @@ private import actions
private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
private import codeql.actions.security.ArtifactPoisoningQuery
private import codeql.actions.security.UntrustedCheckoutQuery
private import codeql.actions.dataflow.FlowSteps
import codeql.actions.DataFlow
import codeql.actions.dataflow.FlowSources
@@ -12,33 +13,48 @@ abstract class EnvVarInjectionSink extends DataFlow::Node { }
* Holds if a Run step declares an environment variable with contents from a local file.
* e.g.
* run: |
* cat test-results/.env >> $GITHUB_ENV
* echo "sha=$(cat test-results/sha-number)" >> $GITHUB_ENV
* echo "sha=$(<test-results/sha-number)" >> $GITHUB_ENV
*/
class EnvVarInjectionFromFileReadSink extends EnvVarInjectionSink {
EnvVarInjectionFromFileReadSink() {
exists(Run run, UntrustedArtifactDownloadStep step, string content, string value |
exists(Run run, Step step |
(
step instanceof UntrustedArtifactDownloadStep or
step instanceof PRHeadCheckoutStep
) and
this.asExpr() = run.getScriptScalar() and
step.getAFollowingStep() = run and
writeToGitHubEnv(run, content) and
extractVariableAndValue(content, _, value) and
(
outputsPartialFileContent(value)
or
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_ENV
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
// cat test-results/.env >> $GITHUB_ENV
fileToGitHubEnv(run, _)
or
exists(string content, string value |
writeToGitHubEnv(run, content) and
extractVariableAndValue(content, _, value) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
// e.g.
// echo "FOO=$(cat test-results/sha-number)" >> $GITHUB_ENV
outputsPartialFileContent(value)
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_ENV
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
)
)
)
)
)

View File

@@ -2,6 +2,7 @@ private import actions
private import codeql.actions.TaintTracking
private import codeql.actions.dataflow.ExternalFlow
private import codeql.actions.security.ArtifactPoisoningQuery
private import codeql.actions.security.UntrustedCheckoutQuery
private import codeql.actions.dataflow.FlowSteps
import codeql.actions.DataFlow
import codeql.actions.dataflow.FlowSources
@@ -12,40 +13,53 @@ abstract class OutputClobberingSink extends DataFlow::Node { }
* Holds if a Run step declares an environment variable with contents from a local file.
* e.g.
* run: |
* cat test-results/.vars >> $GITHUB_OUTPUT
* echo "sha=$(cat test-results/sha-number)" >> $GITHUB_OUTPUT
* echo "sha=$(<test-results/sha-number)" >> $GITHUB_OUTPUT
*/
class OutputClobberingFromFileReadSink extends OutputClobberingSink {
OutputClobberingFromFileReadSink() {
exists(Run run, UntrustedArtifactDownloadStep step, string content, string key, string value |
exists(Run run, Step step |
(
step instanceof UntrustedArtifactDownloadStep or
step instanceof PRHeadCheckoutStep
) and
this.asExpr() = run.getScriptScalar() and
step.getAFollowingStep() = run and
writeToGitHubOutput(run, content) and
extractVariableAndValue(content, key, value) and
// there is a different output variable in the same script
// TODO: key2/value2 should be declared before key/value
exists(string content2, string key2 |
writeToGitHubOutput(run, content2) and
extractVariableAndValue(content2, key2, _) and
not key2 = key
) and
(
outputsPartialFileContent(value)
or
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_OUTPUT
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
// cat test-results/.vars >> $GITHUB_OUTPUT
fileToGitHubOutput(run, _)
or
exists(string content, string key, string value |
writeToGitHubOutput(run, content) and
extractVariableAndValue(content, key, value) and
// there is a different output variable in the same script
// TODO: key2/value2 should be declared before key/value
exists(string content2, string key2 |
writeToGitHubOutput(run, content2) and
extractVariableAndValue(content2, key2, _) and
not key2 = key
) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
outputsPartialFileContent(value)
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
// e.g.
// FOO=$(cat test-results/sha-number)
// echo "FOO=$FOO" >> $GITHUB_OUTPUT
exists(string line, string var_name, string var_value |
run.getScript().splitAt("\n") = line
|
var_name = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 1) and
var_value = line.regexpCapture("([a-zA-Z0-9\\-_]+)=(.*)", 2) and
outputsPartialFileContent(var_value) and
(
value.matches("%$" + ["", "{", "ENV{"] + var_name + "%")
or
value.regexpMatch("\\$\\((echo|printf|write-output)\\s+.*") and
value.indexOf(var_name) > 0
)
)
)
)
)

View File

@@ -0,0 +1,28 @@
name: Build and Dockerize
on:
pull_request_target:
jobs:
build:
name: Test
runs-on: ubuntu-latest
steps:
- name: Decide Which 'ref' To Checkout
id: decide-ref
run: |
if [[ "${{github.event_name}}" == "pull_request_target" ]]; then
echo "ref=refs/pull/${{ github.event.pull_request.number }}/merge" >> $GITHUB_OUTPUT
else
echo "ref=${{github.ref}}" >> $GITHUB_OUTPUT
fi
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{steps.decide-ref.outputs.ref}}
path: "foo"
- name: Read Java Config
run: cat foo/.github/java-config.env >> $GITHUB_ENV

View File

@@ -19,6 +19,7 @@ edges
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:37:14:38:82 | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | provenance | |
nodes
| .github/workflows/test2.yml:12:9:41:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | semmle.label | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -58,6 +59,8 @@ nodes
| .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | semmle.label | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | semmle.label | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | semmle.label | cat foo/.github/java-config.env >> $GITHUB_ENV |
subpaths
#select
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | .github/workflows/test2.yml:12:9:41:6 | Uses Step | .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -80,3 +83,4 @@ subpaths
| .github/workflows/test8.yml:37:14:38:82 | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:37:14:38:82 | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test8.yml:37:14:38:82 | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n |
| .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n |
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | Potential environment variable injection in $@, which may be controlled by an external user. | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | cat foo/.github/java-config.env >> $GITHUB_ENV |

View File

@@ -19,6 +19,7 @@ edges
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:37:14:38:82 | echo "foo=$(cat ./artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test8.yml:26:9:32:6 | Uses Step | .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | provenance | |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | provenance | |
nodes
| .github/workflows/test2.yml:12:9:41:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test2.yml:41:14:43:52 | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n | semmle.label | unzip pr.zip\necho "pr_number=$(cat NR)" >> $GITHUB_ENV\n |
@@ -58,5 +59,7 @@ nodes
| .github/workflows/test8.yml:40:14:41:79 | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n | semmle.label | echo "foo=$(< /artifacts/parent-artifacts/event.txt)" >> $GITHUB_ENV\n |
| .github/workflows/test9.yml:19:9:27:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test9.yml:29:14:41:41 | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n | semmle.label | pr_num=$(jq -r '.pull_request.number' artifacts/event_file/event.json)\nif [ -z "$pr_num" ] \|\| [ "$pr_num" == "null" ]; then\n pr_num=""\nfi\n\nref=$pr_num\nif [ -z "$ref" ] \|\| [ "$ref" == "null" ]; then\n ref=${{ github.ref }}\nfi\n\necho "pr_num=$pr_num" >> $GITHUB_ENV\necho "ref=$ref" >> $GITHUB_ENV\n |
| .github/workflows/test10.yml:20:9:26:6 | Uses Step | semmle.label | Uses Step |
| .github/workflows/test10.yml:27:14:27:59 | cat foo/.github/java-config.env >> $GITHUB_ENV | semmle.label | cat foo/.github/java-config.env >> $GITHUB_ENV |
subpaths
#select