@@ -3,6 +3,8 @@ private import codeql.actions.TaintTracking
3
3
private import codeql.actions.dataflow.ExternalFlow
4
4
import codeql.actions.dataflow.FlowSources
5
5
import codeql.actions.DataFlow
6
+ import codeql.actions.security.ControlChecks
7
+ import codeql.actions.security.CachePoisoningQuery
6
8
7
9
class CodeInjectionSink extends DataFlow:: Node {
8
10
CodeInjectionSink ( ) {
@@ -11,6 +13,46 @@ class CodeInjectionSink extends DataFlow::Node {
11
13
}
12
14
}
13
15
16
+ /**
17
+ * Get the relevant event for the sink in CodeInjectionCritical.ql.
18
+ */
19
+ Event getRelevantCriticalEventForSink ( DataFlow:: Node sink ) {
20
+ inPrivilegedContext ( sink .asExpr ( ) , result ) and
21
+ not exists ( ControlCheck check | check .protects ( sink .asExpr ( ) , result , "code-injection" ) ) and
22
+ // exclude cases where the sink is a JS script and the expression uses toJson
23
+ not exists ( UsesStep script |
24
+ script .getCallee ( ) = "actions/github-script" and
25
+ script .getArgumentExpr ( "script" ) = sink .asExpr ( ) and
26
+ exists ( getAToJsonReferenceExpression ( sink .asExpr ( ) .( Expression ) .getExpression ( ) , _) )
27
+ )
28
+ }
29
+
30
+ /**
31
+ * Get the relevant event for the sink in CachePoisoningViaCodeInjection.ql.
32
+ */
33
+ Event getRelevantCachePoisoningEventForSink ( DataFlow:: Node sink ) {
34
+ exists ( LocalJob job |
35
+ job = sink .asExpr ( ) .getEnclosingJob ( ) and
36
+ job .getATriggerEvent ( ) = result and
37
+ // job can be triggered by an external user
38
+ result .isExternallyTriggerable ( ) and
39
+ // excluding privileged workflows since they can be exploited in easier circumstances
40
+ // which is covered by `actions/code-injection/critical`
41
+ not job .isPrivilegedExternallyTriggerable ( result ) and
42
+ (
43
+ // the workflow runs in the context of the default branch
44
+ runsOnDefaultBranch ( result )
45
+ or
46
+ // the workflow caller runs in the context of the default branch
47
+ result .getName ( ) = "workflow_call" and
48
+ exists ( ExternalJob caller |
49
+ caller .getCallee ( ) = job .getLocation ( ) .getFile ( ) .getRelativePath ( ) and
50
+ runsOnDefaultBranch ( caller .getATriggerEvent ( ) )
51
+ )
52
+ )
53
+ )
54
+ }
55
+
14
56
/**
15
57
* A taint-tracking configuration for unsafe user input
16
58
* that is used to construct and evaluate a code script.
@@ -35,6 +77,18 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
35
77
exists ( run .getScript ( ) .getAFileReadCommand ( ) )
36
78
)
37
79
}
80
+
81
+ predicate observeDiffInformedIncrementalMode ( ) { any ( ) }
82
+
83
+ Location getASelectedSourceLocation ( DataFlow:: Node source ) { none ( ) }
84
+
85
+ Location getASelectedSinkLocation ( DataFlow:: Node sink ) {
86
+ result = sink .getLocation ( )
87
+ or
88
+ result = getRelevantCriticalEventForSink ( sink ) .getLocation ( )
89
+ or
90
+ result = getRelevantCachePoisoningEventForSink ( sink ) .getLocation ( )
91
+ }
38
92
}
39
93
40
94
/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */
0 commit comments