@@ -3,6 +3,8 @@ private import codeql.actions.TaintTracking
33private import codeql.actions.dataflow.ExternalFlow
44import codeql.actions.dataflow.FlowSources
55import codeql.actions.DataFlow
6+ import codeql.actions.security.ControlChecks
7+ import codeql.actions.security.CachePoisoningQuery
68
79class CodeInjectionSink extends DataFlow:: Node {
810 CodeInjectionSink ( ) {
@@ -36,8 +38,51 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
3638 )
3739 }
3840
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+ )
4186 }
4287}
4388
0 commit comments