feat(triggers): New query for critical issues

Adds a new query and the required changes to be able to account for the trigger events so that we dont report issues if they are not likely exploitable.
This commit is contained in:
Alvaro Muñoz
2024-02-21 10:23:37 +01:00
parent a2210dca79
commit 3814462266
11 changed files with 50 additions and 43 deletions

View File

@@ -22,7 +22,9 @@ class AstNode instanceof YamlNode {
*/
class Statement extends AstNode {
/** Gets the workflow that this job is a part of. */
WorkflowStmt getEnclosingWorkflowStmt() { exists(WorkflowStmt w | w.getAChildNode*() = result) }
WorkflowStmt getEnclosingWorkflowStmt() {
exists(WorkflowStmt w | w.getAChildNode*() = this and result = w)
}
}
/**

View File

@@ -39,8 +39,10 @@ predicate sinkModel(string action, string version, string input, string kind) {
Extensions::sinkModel(action, version, input, kind)
}
predicate externallyDefinedSource(DataFlow::Node source, string sourceType, string fieldName) {
exists(UsesExpr uses, string action, string version, string trigger, string kind |
predicate externallyDefinedSource(
DataFlow::Node source, string sourceType, string fieldName, string trigger
) {
exists(UsesExpr uses, string action, string version, string kind |
sourceModel(action, version, fieldName, trigger, kind) and
uses.getCallee() = action.toLowerCase() and
(

View File

@@ -17,6 +17,8 @@ abstract class RemoteFlowSource extends SourceNode {
/** Gets a string that describes the type of this remote flow source. */
abstract string getSourceType();
abstract string getATriggerEvent();
override string getThreatModel() { result = "remote" }
}
@@ -109,20 +111,33 @@ private predicate isExternalUserControlledWorkflowRun(string context) {
}
private class EventSource extends RemoteFlowSource {
string trigger;
EventSource() {
exists(ExprAccessExpr e, string context | this.asExpr() = e and context = e.getExpression() |
isExternalUserControlledIssue(context) or
isExternalUserControlledPullRequest(context) or
isExternalUserControlledReview(context) or
isExternalUserControlledComment(context) or
isExternalUserControlledGollum(context) or
isExternalUserControlledCommit(context) or
isExternalUserControlledDiscussion(context) or
isExternalUserControlledWorkflowRun(context)
trigger = ["issues", "issue_comment"] and isExternalUserControlledIssue(context)
or
trigger = ["pull_request_target", "pull_request_review", "pull_request_review_comment"] and
isExternalUserControlledPullRequest(context)
or
trigger = ["pull_request_review"] and isExternalUserControlledReview(context)
or
trigger = ["pull_request_review_comment", "issue_comment", "discussion_comment"] and
isExternalUserControlledComment(context)
or
trigger = ["gollum"] and isExternalUserControlledGollum(context)
or
trigger = ["push"] and isExternalUserControlledCommit(context)
or
trigger = ["discussion", "discussion_comment"] and isExternalUserControlledDiscussion(context)
or
trigger = ["workflow_run"] and isExternalUserControlledWorkflowRun(context)
)
}
override string getSourceType() { result = "User-controlled events" }
override string getATriggerEvent() { result = trigger }
}
/**
@@ -130,10 +145,13 @@ private class EventSource extends RemoteFlowSource {
*/
private class ExternallyDefinedSource extends RemoteFlowSource {
string sourceType;
string trigger;
ExternallyDefinedSource() { externallyDefinedSource(this, sourceType, _) }
ExternallyDefinedSource() { externallyDefinedSource(this, sourceType, _, trigger) }
override string getSourceType() { result = sourceType }
override string getATriggerEvent() { result = trigger }
}
/**
@@ -145,4 +163,6 @@ private class CompositeActionInputSource extends RemoteFlowSource {
CompositeActionInputSource() { c.getInputsStmt().getInputExpr(_) = this.asExpr() }
override string getSourceType() { result = "Composite action input" }
override string getATriggerEvent() { result = "*" }
}

View File

@@ -173,7 +173,7 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos =
*/
predicate stepsCtxLocalStep(Node nodeFrom, Node nodeTo) {
exists(UsesExpr astFrom, StepsCtxAccessExpr astTo |
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName()) and
externallyDefinedSource(nodeFrom, _, "output." + astTo.getFieldName(), _) and
astFrom = nodeFrom.asExpr() and
astTo = nodeTo.asExpr() and
astTo.getRefExpr() = astFrom
@@ -201,7 +201,7 @@ 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.getRefExpr() = astFrom
)
)

View File

@@ -3,7 +3,5 @@ extensions:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
- ["ahmadnassri/action-changed-files", "*", "output.files", "pull_request", "PR changed files"]
- ["ahmadnassri/action-changed-files", "*", "output.files", "pull_request_target", "PR changed files"]
- ["ahmadnassri/action-changed-files", "*", "output.json", "pull_request", "PR changed files"]
- ["ahmadnassri/action-changed-files", "*", "output.json", "pull_request_target", "PR changed files"]

View File

@@ -3,5 +3,4 @@ extensions:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
- ["dorny/paths-filter", "*", "output.changes", "pull_request", "PR changed files"]
- ["dorny/paths-filter", "*", "output.changes", "pull_request_target", "PR changed files"]

View File

@@ -3,17 +3,10 @@ extensions:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
- ["jitterbit/get-changed-files", "*", "output.all", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.all", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.added", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.added", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.modified", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.modified", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.removed", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.removed", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.renamed", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.renamed", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.added_modified", "pull_request_target", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request", "PR changed files"]
- ["jitterbit/get-changed-files", "*", "output.deleted", "pull_request_target", "PR changed files"]

View File

@@ -0,0 +1,11 @@
extensions:
- addsTo:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
# https://github.com/tj-actions/branch-names
- ["tj-actions/branch-names", "*", "output.base_ref_branch", "pull_request_target", "PR base branch"]
- ["tj-actions/branch-names", "*", "output.current_branch", "pull_request_target", "PR current branch"]
- ["tj-actions/branch-names", "*", "output.head_ref_branch", "pull_request_target", "PR head branch"]
- ["tj-actions/branch-names", "*", "output.ref_branch", "pull_request_target", "Branch tirggering workflow run"]

View File

@@ -3,37 +3,20 @@ extensions:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
- ["tj-actions/changed-files", "*", "output.added_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.added_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.copied_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.copied_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.deleted_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.deleted_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.modified_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.modified_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.renamed_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.renamed_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_old_new_renamed_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_old_new_renamed_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.type_changed_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.type_changed_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.unmerged_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.unmerged_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.unknown_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.unknown_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_changed_and_modified_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_changed_and_modified_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_changed_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_changed_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_changed_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_changed_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_modified_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.all_modified_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_modified_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_modified_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_deleted_files", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.other_deleted_files", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.modified_keys", "pull_request_target", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request", "PR changed files"]
- ["tj-actions/changed-files", "*", "output.changed_keys", "pull_request_target", "PR changed files"]

View File

@@ -3,5 +3,4 @@ extensions:
pack: githubsecuritylab/actions-all
extensible: sourceModel
data:
- ["tj-actions/verify-changed-files", "*", "output.changed-files", "pull_request", "PR changed files"]
- ["tj-actions/verify-changed-files", "*", "output.changed-files", "pull_request_target", "PR changed files"]

View File

@@ -42,6 +42,6 @@ where
.asExpr()
.(Statement)
.getEnclosingWorkflowStmt()
.hasTriggerEvent("pull_request_target")
.hasTriggerEvent(source.getNode().(RemoteFlowSource).getATriggerEvent())
select sink.getNode(), source, sink,
"Potential expression injection, which may be controlled by an external user."