@@ -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 ( ) {
@@ -11,6 +13,46 @@ class CodeInjectionSink extends DataFlow::Node {
1113 }
1214}
1315
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+
1456/**
1557 * A taint-tracking configuration for unsafe user input
1658 * that is used to construct and evaluate a code script.
@@ -35,6 +77,18 @@ private module CodeInjectionConfig implements DataFlow::ConfigSig {
3577 exists ( run .getScript ( ) .getAFileReadCommand ( ) )
3678 )
3779 }
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+ }
3892}
3993
4094/** Tracks flow of unsafe user input that is used to construct and evaluate a code script. */
0 commit comments