diff --git a/actions/ql/lib/codeql/actions/security/ArgumentInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/ArgumentInjectionQuery.qll index 1d461cca3df2..6ac385c78d31 100644 --- a/actions/ql/lib/codeql/actions/security/ArgumentInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/ArgumentInjectionQuery.qll @@ -1,6 +1,7 @@ private import actions private import codeql.actions.TaintTracking private import codeql.actions.dataflow.ExternalFlow +private import codeql.actions.security.ControlChecks import codeql.actions.dataflow.FlowSources import codeql.actions.DataFlow @@ -88,6 +89,19 @@ private module ArgumentInjectionConfig implements DataFlow::ConfigSig { run.getScript().getAnEnvReachingArgumentInjectionSink(var, _, _) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + exists(Event event | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + not exists(ControlCheck check | check.protects(sink.asExpr(), event, "argument-injection")) + ) + } } /** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */ diff --git a/actions/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll b/actions/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll index f0649bb8174e..b6480a53fc9a 100644 --- a/actions/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll +++ b/actions/ql/lib/codeql/actions/security/ArtifactPoisoningQuery.qll @@ -4,6 +4,7 @@ import codeql.actions.DataFlow import codeql.actions.dataflow.FlowSources import codeql.actions.security.PoisonableSteps import codeql.actions.security.UntrustedCheckoutQuery +import codeql.actions.security.ControlChecks string unzipRegexp() { result = "(unzip|tar)\\s+.*" } @@ -318,6 +319,19 @@ private module ArtifactPoisoningConfig implements DataFlow::ConfigSig { exists(run.getScript().getAFileReadCommand()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + exists(Event event | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + not exists(ControlCheck check | check.protects(sink.asExpr(), event, "artifact-poisoning")) + ) + } } /** Tracks flow of unsafe artifacts that is used in an insecure way. */ diff --git a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll index fac498f72dab..a75ac84ef772 100644 --- a/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll @@ -3,6 +3,8 @@ private import codeql.actions.TaintTracking private import codeql.actions.dataflow.ExternalFlow import codeql.actions.dataflow.FlowSources import codeql.actions.DataFlow +import codeql.actions.security.ControlChecks +import codeql.actions.security.CachePoisoningQuery class CodeInjectionSink extends DataFlow::Node { CodeInjectionSink() { @@ -35,6 +37,53 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig { exists(run.getScript().getAFileReadCommand()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + // where clause from CodeInjectionCritical.ql + exists(Event event, RemoteFlowSource source | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + isSource(source) and + source.getEventName() = event.getName() and + not exists(ControlCheck check | check.protects(sink.asExpr(), event, "code-injection")) and + // exclude cases where the sink is a JS script and the expression uses toJson + not exists(UsesStep script | + script.getCallee() = "actions/github-script" and + script.getArgumentExpr("script") = sink.asExpr() and + exists(getAToJsonReferenceExpression(sink.asExpr().(Expression).getExpression(), _)) + ) + ) + or + // where clause from CachePoisoningViaCodeInjection.ql + exists(Event event, LocalJob job, DataFlow::Node source | result = event.getLocation() | + job = sink.asExpr().getEnclosingJob() and + job.getATriggerEvent() = event and + // job can be triggered by an external user + event.isExternallyTriggerable() and + // the checkout is not controlled by an access check + isSource(source) and + not exists(ControlCheck check | check.protects(source.asExpr(), event, "code-injection")) and + // excluding privileged workflows since they can be exploited in easier circumstances + // which is covered by `actions/code-injection/critical` + not job.isPrivilegedExternallyTriggerable(event) and + ( + // the workflow runs in the context of the default branch + runsOnDefaultBranch(event) + or + // the workflow caller runs in the context of the default branch + event.getName() = "workflow_call" and + exists(ExternalJob caller | + caller.getCallee() = job.getLocation().getFile().getRelativePath() and + runsOnDefaultBranch(caller.getATriggerEvent()) + ) + ) + ) + } } /** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */ diff --git a/actions/ql/lib/codeql/actions/security/CommandInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/CommandInjectionQuery.qll index 59d523cd5827..878b7a598056 100644 --- a/actions/ql/lib/codeql/actions/security/CommandInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/CommandInjectionQuery.qll @@ -3,6 +3,7 @@ private import codeql.actions.TaintTracking private import codeql.actions.dataflow.ExternalFlow import codeql.actions.dataflow.FlowSources import codeql.actions.DataFlow +import codeql.actions.security.ControlChecks private class CommandInjectionSink extends DataFlow::Node { CommandInjectionSink() { madSink(this, "command-injection") } @@ -16,6 +17,22 @@ private module CommandInjectionConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) { sink instanceof CommandInjectionSink } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + // where clause from CommandInjectionCritical.ql + exists(Event event | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + not exists(ControlCheck check | + check.protects(sink.asExpr(), event, ["command-injection", "code-injection"]) + ) + ) + } } /** Tracks flow of unsafe user input that is used to construct and evaluate a system command. */ diff --git a/actions/ql/lib/codeql/actions/security/EnvPathInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/EnvPathInjectionQuery.qll index 33efc9b1bc8f..0ed0d2a877e9 100644 --- a/actions/ql/lib/codeql/actions/security/EnvPathInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/EnvPathInjectionQuery.qll @@ -108,6 +108,30 @@ private module EnvPathInjectionConfig implements DataFlow::ConfigSig { exists(run.getScript().getAFileReadCommand()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + // where clause from EnvPathInjectionCritical.ql + exists(Event event, RemoteFlowSource source | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + isSource(source) and + ( + not source.getSourceType() = "artifact" and + not exists(ControlCheck check | check.protects(sink.asExpr(), event, "code-injection")) + or + source.getSourceType() = "artifact" and + not exists(ControlCheck check | + check.protects(sink.asExpr(), event, ["untrusted-checkout", "artifact-poisoning"]) + ) and + sink instanceof EnvPathInjectionFromFileReadSink + ) + ) + } } /** Tracks flow of unsafe user input that is used to construct and evaluate the PATH environment variable. */ diff --git a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll index 656ea1207b51..a99c346e16d3 100644 --- a/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll +++ b/actions/ql/lib/codeql/actions/security/EnvVarInjectionQuery.qll @@ -163,6 +163,40 @@ private module EnvVarInjectionConfig implements DataFlow::ConfigSig { exists(run.getScript().getAFileReadCommand()) ) } + + predicate observeDiffInformedIncrementalMode() { any() } + + Location getASelectedSourceLocation(DataFlow::Node source) { none() } + + Location getASelectedSinkLocation(DataFlow::Node sink) { + result = sink.getLocation() + or + // where clause from EnvVarInjectionCritical.ql + exists(Event event, RemoteFlowSource source | result = event.getLocation() | + inPrivilegedContext(sink.asExpr(), event) and + isSource(source) and + // exclude paths to file read sinks from non-artifact sources + ( + // source is text + not source.getSourceType() = "artifact" and + not exists(ControlCheck check | + check.protects(sink.asExpr(), event, ["envvar-injection", "code-injection"]) + ) + or + // source is an artifact or a file from an untrusted checkout + source.getSourceType() = "artifact" and + not exists(ControlCheck check | + check + .protects(sink.asExpr(), event, + ["envvar-injection", "untrusted-checkout", "artifact-poisoning"]) + ) and + ( + sink instanceof EnvVarInjectionFromFileReadSink or + madSink(sink, "envvar-injection") + ) + ) + ) + } } /** Tracks flow of unsafe user input that is used to construct and evaluate an environment variable. */
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: