Skip to content

Commit 35dbe85

Browse files
committed
1 parent f1e1f80 commit 35dbe85

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

actions/ql/lib/codeql/actions/security/CodeInjectionQuery.qll

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ private import codeql.actions.TaintTracking
33
private import codeql.actions.dataflow.ExternalFlow
44
import codeql.actions.dataflow.FlowSources
55
import codeql.actions.DataFlow
6+
import codeql.actions.security.ControlChecks
7+
import codeql.actions.security.CachePoisoningQuery
68

79
class CodeInjectionSink extends DataFlow::Node {
810
CodeInjectionSink() {
@@ -35,6 +37,53 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
3537
exists(run.getScript().getAFileReadCommand())
3638
)
3739
}
40+
41+
predicate observeDiffInformedIncrementalMode() { any() }
42+
43+
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
44+
45+
Location getASelectedSinkLocation(DataFlow::Node sink) {
46+
result = sink.getLocation()
47+
or
48+
// where clause from CodeInjectionCritical.ql
49+
exists(Event event, RemoteFlowSource source | result = event.getLocation() |
50+
inPrivilegedContext(sink.asExpr(), event) and
51+
isSource(source) and
52+
source.getEventName() = event.getName() and
53+
not exists(ControlCheck check | check.protects(sink.asExpr(), event, "code-injection")) and
54+
// exclude cases where the sink is a JS script and the expression uses toJson
55+
not exists(UsesStep script |
56+
script.getCallee() = "actions/github-script" and
57+
script.getArgumentExpr("script") = sink.asExpr() and
58+
exists(getAToJsonReferenceExpression(sink.asExpr().(Expression).getExpression(), _))
59+
)
60+
)
61+
or
62+
// where clause from CachePoisoningViaCodeInjection.ql
63+
exists(Event event, LocalJob job, DataFlow::Node source | result = event.getLocation() |
64+
job = sink.asExpr().getEnclosingJob() and
65+
job.getATriggerEvent() = event and
66+
// job can be triggered by an external user
67+
event.isExternallyTriggerable() and
68+
// the checkout is not controlled by an access check
69+
isSource(source) and
70+
not exists(ControlCheck check | check.protects(source.asExpr(), event, "code-injection")) and
71+
// excluding privileged workflows since they can be exploited in easier circumstances
72+
// which is covered by `actions/code-injection/critical`
73+
not job.isPrivilegedExternallyTriggerable(event) and
74+
(
75+
// the workflow runs in the context of the default branch
76+
runsOnDefaultBranch(event)
77+
or
78+
// the workflow caller runs in the context of the default branch
79+
event.getName() = "workflow_call" and
80+
exists(ExternalJob caller |
81+
caller.getCallee() = job.getLocation().getFile().getRelativePath() and
82+
runsOnDefaultBranch(caller.getATriggerEvent())
83+
)
84+
)
85+
)
86+
}
3887
}
3988

4089
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */

0 commit comments

Comments
 (0)