mirror of
https://github.com/github/codeql.git
synced 2026-01-07 19:50:22 +01:00
Add Artifact poisoning and Env Injection queries
This commit is contained in:
@@ -38,7 +38,9 @@ class AstNode instanceof AstNodeImpl {
|
||||
Expression getInScopeEnvVarExpr(string name) { result = super.getInScopeEnvVarExpr(name) }
|
||||
}
|
||||
|
||||
class ScalarValue extends AstNode instanceof ScalarValueImpl { }
|
||||
class ScalarValue extends AstNode instanceof ScalarValueImpl {
|
||||
string getValue() { result = super.getValue() }
|
||||
}
|
||||
|
||||
class Expression extends AstNode instanceof ExpressionImpl {
|
||||
string expression;
|
||||
@@ -218,6 +220,8 @@ abstract class Uses extends AstNode instanceof UsesImpl {
|
||||
|
||||
string getVersion() { result = super.getVersion() }
|
||||
|
||||
string getArgument(string argName) { result = super.getArgument(argName) }
|
||||
|
||||
Expression getArgumentExpr(string argName) { result = super.getArgumentExpr(argName) }
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,8 @@ class ScalarValueImpl extends AstNodeImpl, TScalarValueNode {
|
||||
override Location getLocation() { result = value.getLocation() }
|
||||
|
||||
override YamlScalar getNode() { result = value }
|
||||
|
||||
string getValue() { result = value.getValue() }
|
||||
}
|
||||
|
||||
class ExpressionImpl extends AstNodeImpl, TExpressionNode {
|
||||
@@ -687,7 +689,19 @@ abstract class UsesImpl extends AstNodeImpl {
|
||||
|
||||
abstract string getVersion();
|
||||
|
||||
abstract ExpressionImpl getArgumentExpr(string key);
|
||||
/** Gets the argument expression for the given key. */
|
||||
string getArgument(string key) {
|
||||
exists(ScalarValueImpl scalar |
|
||||
scalar.getNode() = this.getNode().(YamlMapping).lookup("with").(YamlMapping).lookup(key) and
|
||||
result = scalar.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the argument expression for the given key (if it exists). */
|
||||
ExpressionImpl getArgumentExpr(string key) {
|
||||
result.getParentNode().getNode() =
|
||||
this.getNode().(YamlMapping).lookup("with").(YamlMapping).lookup(key)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -719,11 +733,6 @@ class UsesStepImpl extends StepImpl, UsesImpl {
|
||||
/** Gets the version reference used when checking out the Action, e.g. `v2` in `actions/checkout@v2`. */
|
||||
override string getVersion() { result = u.getValue().regexpCapture(usesParser(), 3) }
|
||||
|
||||
/** Gets the argument expression for the given key. */
|
||||
override ExpressionImpl getArgumentExpr(string key) {
|
||||
result.getParentNode().getNode() = n.lookup("with").(YamlMapping).lookup(key)
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
if exists(this.getId()) then result = "Uses Step: " + this.getId() else result = "Uses Step"
|
||||
}
|
||||
@@ -763,11 +772,6 @@ class ExternalJobImpl extends JobImpl, UsesImpl {
|
||||
else none()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the argument expression for the given key. */
|
||||
override ExpressionImpl getArgumentExpr(string key) {
|
||||
result.getParentNode().getNode() = n.lookup("with").(YamlMapping).lookup(key)
|
||||
}
|
||||
}
|
||||
|
||||
class RunImpl extends StepImpl {
|
||||
|
||||
@@ -33,12 +33,12 @@ class AdditionalTaintStep extends Unit {
|
||||
* echo "foo=$(echo $BODY)" >> $GITHUB_OUTPUT
|
||||
* echo "foo=$(echo $BODY)" >> "$GITHUB_OUTPUT"
|
||||
*/
|
||||
predicate runEnvToScriptStoreStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::ContentSet c) {
|
||||
exists(Run r, string varName, string 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
|
||||
r.getInScopeEnvVarExpr(varName) = pred.asExpr() and
|
||||
run.getInScopeEnvVarExpr(varName) = pred.asExpr() and
|
||||
exists(string script, string line |
|
||||
script = r.getScript() and
|
||||
script = run.getScript() and
|
||||
line = script.splitAt("\n") and
|
||||
(
|
||||
output = line.regexpCapture(".*::set-output\\s+name=(.*)::.*", 1) or
|
||||
@@ -46,6 +46,6 @@ predicate runEnvToScriptStoreStep(DataFlow::Node pred, DataFlow::Node succ, Data
|
||||
) and
|
||||
line.indexOf("$" + ["", "{", "ENV{"] + varName) > 0
|
||||
) and
|
||||
succ.asExpr() = r
|
||||
succ.asExpr() = run
|
||||
)
|
||||
}
|
||||
|
||||
@@ -232,8 +232,24 @@ predicate envCtxLocalStep(Node nodeFrom, Node nodeTo) {
|
||||
astFrom = nodeFrom.asExpr() and
|
||||
astTo = nodeTo.asExpr() and
|
||||
(
|
||||
externallyDefinedSource(nodeFrom, _, "env." + astTo.getFieldName()) or
|
||||
externallyDefinedSource(nodeFrom, _, "env." + astTo.getFieldName())
|
||||
or
|
||||
astTo.getTarget() = astFrom
|
||||
or
|
||||
// e.g:
|
||||
// - run: echo ISSUE_KEY=$(echo "${{ github.event.pull_request.title }}") >> $GITHUB_ENV
|
||||
// - run: echo ${{ env.ISSUE_KEY }}
|
||||
exists(Run run, string script, Expression expr, string line, string key, string value |
|
||||
run.getScript() = script and
|
||||
run.getAnScriptExpr() = expr and
|
||||
line = script.splitAt("\n") and
|
||||
key = line.regexpCapture("echo\\s+([^=]+)\\s*=(.*)>>\\s*\\$GITHUB_ENV", 1) and
|
||||
value = line.regexpCapture("echo\\s+([^=]+)\\s*=(.*)>>\\s*\\$GITHUB_ENV", 2) and
|
||||
value.indexOf(expr.getRawExpression()) > 0 and
|
||||
key = astTo.getFieldName() and
|
||||
expr = astFrom and
|
||||
expr.getEnclosingWorkflow() = run.getEnclosingWorkflow()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -312,7 +328,7 @@ predicate fieldStoreStep(Node node1, Node node2, ContentSet c) {
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
fieldStoreStep(node1, node2, c) or
|
||||
externallyDefinedStoreStep(node1, node2, c) or
|
||||
runEnvToScriptStoreStep(node1, node2, c)
|
||||
envToOutputStoreStep(node1, node2, c)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
50
ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll
Normal file
50
ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll
Normal file
@@ -0,0 +1,50 @@
|
||||
import actions
|
||||
|
||||
class ArtifactDownloadStep extends Step {
|
||||
ArtifactDownloadStep() {
|
||||
// eg: - uses: dawidd6/action-download-artifact@v2
|
||||
this.(UsesStep).getCallee() = "dawidd6/action-download-artifact" and
|
||||
// exclude downloads outside the current directory
|
||||
// TODO: add more checks to make sure the artifacts can be controlled
|
||||
not exists(this.(UsesStep).getArgumentExpr("path"))
|
||||
or
|
||||
// eg:
|
||||
// - uses: actions/github-script@v6
|
||||
// with:
|
||||
// script: |
|
||||
// let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
// owner: context.repo.owner,
|
||||
// repo: context.repo.repo,
|
||||
// run_id: context.payload.workflow_run.id,
|
||||
// });
|
||||
// let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
|
||||
// return artifact.name == "<ARTEFACT_NAME>"
|
||||
// })[0];
|
||||
// let download = await github.rest.actions.downloadArtifact({
|
||||
// owner: context.repo.owner,
|
||||
// repo: context.repo.repo,
|
||||
// artifact_id: matchArtifact.id,
|
||||
// archive_format: 'zip',
|
||||
// });
|
||||
this.(UsesStep).getCallee() = "actions/github-script" and
|
||||
exists(string script |
|
||||
this.(UsesStep).getArgument("script") = script and
|
||||
script.matches("%listWorkflowRunArtifacts(%") and
|
||||
script.matches("%downloadArtifact(%")
|
||||
)
|
||||
or
|
||||
// eg: - run: gh run download "${WORKFLOW_RUN_ID}" --repo "${GITHUB_REPOSITORY}" --name "artifact_name"
|
||||
this.(Run).getScript().splitAt("\n").regexpMatch(".*gh\\s+run\\s+download.*")
|
||||
or
|
||||
// eg:
|
||||
// run: |
|
||||
// artifacts_url=${{ github.event.workflow_run.artifacts_url }}
|
||||
// gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact
|
||||
// do
|
||||
// IFS=$'\t' read name url <<< "$artifact"
|
||||
// gh api $url > "$name.zip"
|
||||
// unzip -d "$name" "$name.zip"
|
||||
// done
|
||||
this.(Run).getScript().splitAt("\n").matches("%github.event.workflow_run.artifacts_url%")
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,13 @@ private import codeql.actions.dataflow.ExternalFlow
|
||||
import codeql.actions.dataflow.FlowSources
|
||||
import codeql.actions.DataFlow
|
||||
|
||||
predicate writeToGithubEnvSink(DataFlow::Node sink) {
|
||||
exists(Expression expr, Run run, string script, string line, string value |
|
||||
predicate writeToGithubEnvSink(DataFlow::Node exprNode, string key, string value) {
|
||||
exists(Expression expr, Run run, string script, string line |
|
||||
script = run.getScript() and
|
||||
line = script.splitAt("\n") and
|
||||
value = line.regexpCapture("echo\\s+.*\\s*=(.*)>>\\s*\\$GITHUB_ENV", 1) and
|
||||
expr = sink.asExpr() and
|
||||
key = line.regexpCapture("echo\\s+([^=]+)\\s*=(.*)>>\\s*\\$GITHUB_ENV", 1) and
|
||||
value = line.regexpCapture("echo\\s+([^=]+)\\s*=(.*)>>\\s*\\$GITHUB_ENV", 2) and
|
||||
expr = exprNode.asExpr() and
|
||||
run.getAnScriptExpr() = expr and
|
||||
value.indexOf(expr.getRawExpression()) > 0
|
||||
)
|
||||
@@ -17,7 +18,7 @@ predicate writeToGithubEnvSink(DataFlow::Node sink) {
|
||||
|
||||
private class EnvVarInjectionSink extends DataFlow::Node {
|
||||
EnvVarInjectionSink() {
|
||||
writeToGithubEnvSink(this) or
|
||||
writeToGithubEnvSink(this, _, _) or
|
||||
externallyDefinedSink(this, "envvar-injection")
|
||||
}
|
||||
}
|
||||
|
||||
26
ql/src/Security/CWE-829/ArtifactPoisoning.ql
Normal file
26
ql/src/Security/CWE-829/ArtifactPoisoning.ql
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @name Artifact poisoning
|
||||
* @description An attacker may be able to poison the workflow's artifacts and influence on consequent steps.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision medium
|
||||
* @security-severity 9.3
|
||||
* @id actions/artifact-poisoning
|
||||
* @tags actions
|
||||
* security
|
||||
* external/cwe/cwe-829
|
||||
*/
|
||||
|
||||
import actions
|
||||
import codeql.actions.security.ArtifactPoisoningQuery
|
||||
|
||||
from LocalJob job, ArtifactDownloadStep download, Step run
|
||||
where
|
||||
job.getWorkflow().getATriggerEvent() = "workflow_run" and
|
||||
(run instanceof Run or run instanceof UsesStep) and
|
||||
exists(int i, int j |
|
||||
job.getStep(i) = download and
|
||||
job.getStep(j) = run and
|
||||
i < j
|
||||
)
|
||||
select download, "Potential artifact poisoning."
|
||||
@@ -5,7 +5,7 @@
|
||||
* that is able to push to the base repository and to access secrets.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision low
|
||||
* @precision medium
|
||||
* @security-severity 9.3
|
||||
* @id actions/untrusted-checkout
|
||||
* @tags actions
|
||||
|
||||
@@ -21,5 +21,7 @@ jobs:
|
||||
- name: Extract Jira Key
|
||||
run: echo ISSUE_KEY=$(echo "${{ github.event.pull_request.title }}") >> $GITHUB_ENV
|
||||
|
||||
- name: Sink
|
||||
run: echo ${{ env.ISSUE_KEY }}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
edges
|
||||
nodes
|
||||
| .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
|
||||
subpaths
|
||||
#select
|
||||
| .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 environment variable 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 }} |
|
||||
@@ -0,0 +1,6 @@
|
||||
edges
|
||||
nodes
|
||||
| .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
|
||||
subpaths
|
||||
#select
|
||||
| .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 environment variable 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 }} |
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
if: ${{ always() }}
|
||||
|
||||
needs: job
|
||||
needs: job1
|
||||
|
||||
steps:
|
||||
- id: sink
|
||||
|
||||
27
ql/test/query-tests/Security/CWE-094/.github/workflows/test1.yml
vendored
Normal file
27
ql/test/query-tests/Security/CWE-094/.github/workflows/test1.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
|
||||
- name: Extract Jira Key
|
||||
run: echo ISSUE_KEY=$(echo "${{ github.event.pull_request.title }}") >> $GITHUB_ENV
|
||||
|
||||
- name: Sink
|
||||
run: echo ${{ env.ISSUE_KEY }}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ edges
|
||||
| .github/workflows/simple2.yml:14:9:18:6 | Uses Step: source | .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files |
|
||||
| .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value |
|
||||
| .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files | .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] |
|
||||
| .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY |
|
||||
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] |
|
||||
| .github/workflows/test.yml:8:20:8:50 | steps.step2.outputs.test | .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] |
|
||||
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | .github/workflows/test.yml:20:18:20:48 | steps.step0.outputs.value |
|
||||
@@ -185,6 +186,9 @@ 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/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 |
|
||||
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] |
|
||||
| .github/workflows/test.yml:8:20:8:50 | steps.step2.outputs.test | semmle.label | steps.step2.outputs.test |
|
||||
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | semmle.label | Uses Step: step0 [value] |
|
||||
@@ -282,6 +286,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 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 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 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/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 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 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:37:20:37:56 | needs.job1.outputs['job_output'] | .github/workflows/test.yml:15:20:15:64 | github.event['head_commit']['message'] | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] | ${{needs.job1.outputs['job_output']}} |
|
||||
| .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 }} |
|
||||
| .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 }} |
|
||||
|
||||
@@ -50,6 +50,7 @@ edges
|
||||
| .github/workflows/simple2.yml:14:9:18:6 | Uses Step: source | .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files |
|
||||
| .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] | .github/workflows/simple2.yml:29:24:29:54 | steps.step.outputs.value |
|
||||
| .github/workflows/simple2.yml:22:20:22:64 | steps.source.outputs.all_changed_files | .github/workflows/simple2.yml:18:9:26:6 | Uses Step: step [value] |
|
||||
| .github/workflows/test1.yml:22:38:22:75 | github.event.pull_request.title | .github/workflows/test1.yml:25:20:25:39 | env.ISSUE_KEY |
|
||||
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] |
|
||||
| .github/workflows/test.yml:8:20:8:50 | steps.step2.outputs.test | .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] |
|
||||
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | .github/workflows/test.yml:20:18:20:48 | steps.step0.outputs.value |
|
||||
@@ -185,6 +186,9 @@ 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/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 |
|
||||
| .github/workflows/test.yml:8:7:10:4 | Job outputs node [job_output] | semmle.label | Job outputs node [job_output] |
|
||||
| .github/workflows/test.yml:8:20:8:50 | steps.step2.outputs.test | semmle.label | steps.step2.outputs.test |
|
||||
| .github/workflows/test.yml:12:9:18:6 | Uses Step: step0 [value] | semmle.label | Uses Step: step0 [value] |
|
||||
@@ -281,6 +285,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/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:37:20:37:56 | needs.job1.outputs['job_output'] | .github/workflows/test.yml:15:20:15:64 | github.event['head_commit']['message'] | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] | Potential privileged code injection in $@, which may be controlled by an external user. | .github/workflows/test.yml:37:20:37:56 | needs.job1.outputs['job_output'] | ${{needs.job1.outputs['job_output']}} |
|
||||
| .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 privileged 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 }} |
|
||||
| .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 privileged 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 }} |
|
||||
|
||||
34
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning1.yml
vendored
Normal file
34
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning1.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Pull Request Open
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Prev"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
Download:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.payload.workflow_run.id,
|
||||
});
|
||||
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
|
||||
return artifact.name == "<ARTEFACT_NAME>"
|
||||
})[0];
|
||||
let download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
- name: Run command
|
||||
run: cmd
|
||||
|
||||
|
||||
|
||||
21
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning2.yml
vendored
Normal file
21
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning2.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Pull Request Open
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Prev"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
Download:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
name: artifact_name
|
||||
workflow: wf.yml
|
||||
- name: Run command
|
||||
run: cmd
|
||||
|
||||
|
||||
|
||||
19
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning3.yml
vendored
Normal file
19
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning3.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Pull Request Open
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Prev"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
Download:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
gh run download "${WORKFLOW_RUN_ID}" --repo "${GITHUB_REPOSITORY}" --name "artifact_name"
|
||||
- name: Run command
|
||||
run: cmd
|
||||
|
||||
|
||||
|
||||
25
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning4.yml
vendored
Normal file
25
ql/test/query-tests/Security/CWE-829/.github/workflows/artifactpoisoning4.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Pull Request Open
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Prev"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
Download:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: |
|
||||
artifacts_url=${{ github.event.workflow_run.artifacts_url }}
|
||||
gh api "$artifacts_url" -q '.artifacts[] | [.name, .archive_download_url] | @tsv' | while read artifact
|
||||
do
|
||||
IFS=$'\t' read name url <<< "$artifact"
|
||||
gh api $url > "$name.zip"
|
||||
unzip -d "$name" "$name.zip"
|
||||
done
|
||||
- name: Run command
|
||||
run: cmd
|
||||
|
||||
|
||||
|
||||
27
ql/test/query-tests/Security/CWE-829/.github/workflows/test1.yml
vendored
Normal file
27
ql/test/query-tests/Security/CWE-829/.github/workflows/test1.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
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
|
||||
|
||||
- name: Extract Jira Key
|
||||
run: echo ISSUE_KEY=$(echo "${{ github.event.pull_request.title }}") >> $GITHUB_ENV
|
||||
|
||||
- name: Sink
|
||||
run: echo ${{ env.ISSUE_KEY }}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
| .github/workflows/artifactpoisoning1.yml:13:9:30:6 | Uses Step | Potential artifact poisoning. |
|
||||
| .github/workflows/artifactpoisoning2.yml:13:9:17:6 | Uses Step | Potential artifact poisoning. |
|
||||
| .github/workflows/artifactpoisoning3.yml:13:9:15:6 | Run Step | Potential artifact poisoning. |
|
||||
| .github/workflows/artifactpoisoning4.yml:13:9:21:6 | Run Step | Potential artifact poisoning. |
|
||||
@@ -0,0 +1,2 @@
|
||||
Security/CWE-829/ArtifactPoisoning.ql
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
| .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | Unpinned 3rd party Action 'actor_trusted_checkout.yml' step $@ uses 'completely/fakeaction' with ref 'v2', not a pinned commit hash | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | Uses Step |
|
||||
| .github/workflows/actor_trusted_checkout.yml:23:7:26:21 | Uses Step | Unpinned 3rd party Action 'actor_trusted_checkout.yml' step $@ uses 'fakerepo/comment-on-pr' with ref 'v1', not a pinned commit hash | .github/workflows/actor_trusted_checkout.yml:23:7:26:21 | Uses Step | Uses Step |
|
||||
| .github/workflows/artifactpoisoning2.yml:13:9:17:6 | Uses Step | Unpinned 3rd party Action 'Pull Request Open' step $@ uses 'dawidd6/action-download-artifact' with ref 'v2', not a pinned commit hash | .github/workflows/artifactpoisoning2.yml:13:9:17:6 | Uses Step | Uses Step |
|
||||
| .github/workflows/auto_ci.yml:93:9:96:6 | Uses Step | Unpinned 3rd party Action 'Python CI' step $@ uses 'codecov/codecov-action' with ref 'v3', not a pinned commit hash | .github/workflows/auto_ci.yml:93:9:96:6 | Uses Step | Uses Step |
|
||||
| .github/workflows/auto_ci.yml:108:9:119:6 | Uses Step: create_pr | Unpinned 3rd party Action 'Python CI' step $@ uses 'peter-evans/create-pull-request' with ref 'v5', not a pinned commit hash | .github/workflows/auto_ci.yml:108:9:119:6 | Uses Step: create_pr | Uses Step: create_pr |
|
||||
| .github/workflows/auto_ci.yml:125:9:133:6 | Uses Step | Unpinned 3rd party Action 'Python CI' step $@ uses 'thollander/actions-comment-pull-request' with ref 'v2', not a pinned commit hash | .github/workflows/auto_ci.yml:125:9:133:6 | Uses Step | Uses Step |
|
||||
|
||||
Reference in New Issue
Block a user