MCPcopy Create free account
hub / github.com/github/gh-aw / validateSingleExpression

Function validateSingleExpression

pkg/workflow/expression_safety_validation.go:180–267  ·  view source on GitHub ↗

validateSingleExpression validates a single literal expression

(expression string, opts ExpressionValidationOptions)

Source from the content-addressed store, hash-verified

178
179// validateSingleExpression validates a single literal expression
180func validateSingleExpression(expression string, opts ExpressionValidationOptions) error {
181 expression = strings.TrimSpace(expression)
182
183 // Allow literal values (string, number, boolean) — safe leaf nodes in compound expressions.
184 if stringLiteralRegex.MatchString(expression) ||
185 numberLiteralRegex.MatchString(expression) ||
186 expression == "true" || expression == "false" {
187 return nil
188 }
189
190 // Check for dangerous JavaScript property names (prototype pollution, PR #14826)
191 if err := validateExpressionForDangerousProps(expression); err != nil {
192 return err
193 }
194
195 // Check if this expression is in the allowed list
196 allowed := false
197
198 if opts.NeedsStepsRe.MatchString(expression) {
199 allowed = true
200 } else if opts.InputsRe.MatchString(expression) {
201 allowed = true
202 } else if opts.WorkflowCallInputsRe.MatchString(expression) {
203 allowed = true
204 } else if opts.AwInputsRe.MatchString(expression) {
205 allowed = true
206 } else if opts.AwImportInputsRe != nil && opts.AwImportInputsRe.MatchString(expression) {
207 allowed = true
208 } else if opts.EnvRe.MatchString(expression) {
209 allowed = true
210 } else if _, ok := constants.AllowedExpressionsSet[expression]; ok {
211 allowed = true
212 }
213
214 // Check for OR expressions with literals (e.g., "inputs.repository || 'default'")
215 if !allowed {
216 orMatch := orExpressionPattern.FindStringSubmatch(expression)
217 if len(orMatch) > 2 {
218 leftExpr := strings.TrimSpace(orMatch[1])
219 rightExpr := strings.TrimSpace(orMatch[2])
220
221 leftErr := validateSingleExpression(leftExpr, opts)
222 leftIsSafe := leftErr == nil && !containsExpressionInList(opts.UnauthorizedExpressions, leftExpr)
223
224 if leftIsSafe {
225 // Check if right side is a literal string (single, double, or backtick quotes)
226 // Note: Using (?:) for non-capturing group and checking each quote type separately
227 isStringLiteral := stringLiteralRegex.MatchString(rightExpr)
228 // Check if right side is a number literal
229 isNumberLiteral := numberLiteralRegex.MatchString(rightExpr)
230 // Check if right side is a boolean literal
231 isBooleanLiteral := rightExpr == "true" || rightExpr == "false"
232
233 if isStringLiteral || isNumberLiteral || isBooleanLiteral {
234 allowed = true
235 } else {
236 // If right side is also a safe expression, recursively check it
237 rightErr := validateSingleExpression(rightExpr, opts)