@@ -103,70 +103,122 @@ private predicate isExternalUserControlledWorkflowRun(string context) {
103
103
)
104
104
}
105
105
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
108
122
(
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
120
157
)
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 )
121
174
)
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 )
137
189
)
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 )
138
221
)
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 )
170
222
)
171
223
select node ,
172
224
"Potential injection from the ${ " + injection +
0 commit comments