@@ -103,70 +103,122 @@ private predicate isExternalUserControlledWorkflowRun(string context) {
103103 )
104104}
105105
106- from YamlNode node , string injection , string context , Actions:: On on
107- where
106+ /**
107+ * The env variable name in `${{ env.name }}`
108+ * is where the external user controlled value was assigned to.
109+ */
110+ bindingset [ injection]
111+ predicate isEnvTainted ( Actions:: Env env , string injection , string context ) {
112+ Actions:: getEnvName ( injection ) = env .getName ( ) and
113+ Actions:: getASimpleReferenceExpression ( env ) = context
114+ }
115+
116+ /**
117+ * Holds if the `run` contains any expression interpolation `${{ e }}`.
118+ * Sets `context` to the initial untrusted value assignment in case of `${{ env... }}` interpolation
119+ */
120+ predicate isRunInjectable ( Actions:: Run run , string injection , string context ) {
121+ Actions:: getASimpleReferenceExpression ( run ) = injection and
108122 (
109- exists ( Actions:: Run run |
110- node = run and
111- Actions:: getASimpleReferenceExpression ( run ) = injection and
112- run .getStep ( ) .getJob ( ) .getWorkflow ( ) .getOn ( ) = on and
113- (
114- injection = context
115- or
116- exists ( Actions:: Env env |
117- Actions:: getEnvName ( injection ) = env .getName ( ) and
118- Actions:: getASimpleReferenceExpression ( env ) = context
119- )
123+ injection = context
124+ or
125+ exists ( Actions:: Env env | isEnvTainted ( env , injection , context ) )
126+ )
127+ }
128+
129+ /**
130+ * Holds if the `actions/github-script` contains any expression interpolation `${{ e }}`.
131+ * Sets `context` to the initial untrusted value assignment in case of `${{ env... }}` interpolation
132+ */
133+ predicate isScriptInjectable ( Actions:: Script script , string injection , string context ) {
134+ exists ( Actions:: Step step , Actions:: Uses uses |
135+ script .getWith ( ) .getStep ( ) = step and
136+ uses .getStep ( ) = step and
137+ uses .getGitHubRepository ( ) = "actions/github-script" and
138+ Actions:: getASimpleReferenceExpression ( script ) = injection and
139+ (
140+ injection = context
141+ or
142+ exists ( Actions:: Env env | isEnvTainted ( env , injection , context ) )
143+ )
144+ )
145+ }
146+
147+ from YamlNode node , string injection , string context
148+ where
149+ exists ( Actions:: Using u , Actions:: Runs runs |
150+ u .getValue ( ) = "composite" and
151+ u .getRuns ( ) = runs and
152+ (
153+ exists ( Actions:: Run run |
154+ isRunInjectable ( run , injection , context ) and
155+ node = run and
156+ run .getStep ( ) .getRuns ( ) = runs
120157 )
158+ or
159+ exists ( Actions:: Script script |
160+ node = script and
161+ script .getWith ( ) .getStep ( ) .getRuns ( ) = runs and
162+ isScriptInjectable ( script , injection , context )
163+ )
164+ ) and
165+ (
166+ isExternalUserControlledIssue ( context ) or
167+ isExternalUserControlledPullRequest ( context ) or
168+ isExternalUserControlledReview ( context ) or
169+ isExternalUserControlledComment ( context ) or
170+ isExternalUserControlledGollum ( context ) or
171+ isExternalUserControlledCommit ( context ) or
172+ isExternalUserControlledDiscussion ( context ) or
173+ isExternalUserControlledWorkflowRun ( context )
121174 )
122- or
123- exists ( Actions:: Script script , Actions:: Step step , Actions:: Uses uses |
124- node = script and
125- script .getWith ( ) .getStep ( ) .getJob ( ) .getWorkflow ( ) .getOn ( ) = on and
126- script .getWith ( ) .getStep ( ) = step and
127- uses .getStep ( ) = step and
128- uses .getGitHubRepository ( ) = "actions/github-script" and
129- Actions:: getASimpleReferenceExpression ( script ) = injection and
130- (
131- injection = context
132- or
133- exists ( Actions:: Env env |
134- Actions:: getEnvName ( injection ) = env .getName ( ) and
135- Actions:: getASimpleReferenceExpression ( env ) = context
136- )
175+ )
176+ or
177+ exists ( Actions:: On on |
178+ (
179+ exists ( Actions:: Run run |
180+ isRunInjectable ( run , injection , context ) and
181+ node = run and
182+ run .getStep ( ) .getJob ( ) .getWorkflow ( ) .getOn ( ) = on
183+ )
184+ or
185+ exists ( Actions:: Script script |
186+ node = script and
187+ script .getWith ( ) .getStep ( ) .getJob ( ) .getWorkflow ( ) .getOn ( ) = on and
188+ isScriptInjectable ( script , injection , context )
137189 )
190+ ) and
191+ (
192+ exists ( on .getNode ( "issues" ) ) and
193+ isExternalUserControlledIssue ( context )
194+ or
195+ exists ( on .getNode ( "pull_request_target" ) ) and
196+ isExternalUserControlledPullRequest ( context )
197+ or
198+ exists ( on .getNode ( "pull_request_review" ) ) and
199+ ( isExternalUserControlledReview ( context ) or isExternalUserControlledPullRequest ( context ) )
200+ or
201+ exists ( on .getNode ( "pull_request_review_comment" ) ) and
202+ ( isExternalUserControlledComment ( context ) or isExternalUserControlledPullRequest ( context ) )
203+ or
204+ exists ( on .getNode ( "issue_comment" ) ) and
205+ ( isExternalUserControlledComment ( context ) or isExternalUserControlledIssue ( context ) )
206+ or
207+ exists ( on .getNode ( "gollum" ) ) and
208+ isExternalUserControlledGollum ( context )
209+ or
210+ exists ( on .getNode ( "push" ) ) and
211+ isExternalUserControlledCommit ( context )
212+ or
213+ exists ( on .getNode ( "discussion" ) ) and
214+ isExternalUserControlledDiscussion ( context )
215+ or
216+ exists ( on .getNode ( "discussion_comment" ) ) and
217+ ( isExternalUserControlledDiscussion ( context ) or isExternalUserControlledComment ( context ) )
218+ or
219+ exists ( on .getNode ( "workflow_run" ) ) and
220+ isExternalUserControlledWorkflowRun ( context )
138221 )
139- ) and
140- (
141- exists ( on .getNode ( "issues" ) ) and
142- isExternalUserControlledIssue ( context )
143- or
144- exists ( on .getNode ( "pull_request_target" ) ) and
145- isExternalUserControlledPullRequest ( context )
146- or
147- exists ( on .getNode ( "pull_request_review" ) ) and
148- ( isExternalUserControlledReview ( context ) or isExternalUserControlledPullRequest ( context ) )
149- or
150- exists ( on .getNode ( "pull_request_review_comment" ) ) and
151- ( isExternalUserControlledComment ( context ) or isExternalUserControlledPullRequest ( context ) )
152- or
153- exists ( on .getNode ( "issue_comment" ) ) and
154- ( isExternalUserControlledComment ( context ) or isExternalUserControlledIssue ( context ) )
155- or
156- exists ( on .getNode ( "gollum" ) ) and
157- isExternalUserControlledGollum ( context )
158- or
159- exists ( on .getNode ( "push" ) ) and
160- isExternalUserControlledCommit ( context )
161- or
162- exists ( on .getNode ( "discussion" ) ) and
163- isExternalUserControlledDiscussion ( context )
164- or
165- exists ( on .getNode ( "discussion_comment" ) ) and
166- ( isExternalUserControlledDiscussion ( context ) or isExternalUserControlledComment ( context ) )
167- or
168- exists ( on .getNode ( "workflow_run" ) ) and
169- isExternalUserControlledWorkflowRun ( context )
170222 )
171223select node ,
172224 "Potential injection from the ${ " + injection +
0 commit comments