@@ -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 ( ) {
@@ -36,8 +38,51 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
36
38
)
37
39
}
38
40
39
- predicate observeDiffInformedIncrementalMode ( ) {
40
- any ( ) // TODO: Make sure that the location overrides match the query's select clause: Column 7 does not select a source or sink originating from the flow call on line 23 (/Users/d10c/src/semmle-code/ql/actions/ql/src/Security/CWE-349/CachePoisoningViaCodeInjection.ql@48:60:48:64), Column 7 does not select a source or sink originating from the flow call on line 24 (/Users/d10c/src/semmle-code/ql/actions/ql/src/Security/CWE-094/CodeInjectionCritical.ql@36:60:36:64)
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
+ )
41
86
}
42
87
}
43
88
0 commit comments