Skip to content

Performance: Linear response time degradation when processing large numbers of validation errors #407

Description

@judah-w

A DoS vulnerability exists in how gqlgen processes queries containing a large number of invalid fields (and presumably other validation errors). When a query contains N instances of an invalid field, the engine attempts to validate and generate an error message for every single instance, leading to (O(N)) growth in processing time before a response is returned.

My suggestion is that there should be an option to abort the walk operation in the validation step once an error has been encountered.

Example:

query DoSQuery {
  user {
    # If repeated many times (e.g. 1000), CPU usage spikes
    nonExistentField 
    nonExistentField
    ...
  }
}

Proposed Solution:

PR with code changes

  • Modify walk.go
type Events struct {
	// ... existing fields

	// StopOnFirstError indicates whether to stop traversal on the first error.
	StopOnFirstError bool

	// Stopped indicates traversal should stop early. This is set by validators
	// that wish to abort walking once an error has been encountered.
	Stopped bool
}
func (w *Walker) walkOperation(operation *ast.OperationDefinition) {
	// Add this logic to all walk methods
	if w.Observers != nil && w.Observers.Stopped {
		return
	}

	// ... existing code
  • Modify validator.go
func ValidateWithRules(schema *Schema, doc *QueryDocument, rules *validatorrules.Rules) gqlerror.List {
	return ValidateWithRulesAndStopOnFirstError(schema, doc, rules, false)
}

func ValidateWithRulesAndStopOnFirstError(schema *Schema, doc *QueryDocument, rules *validatorrules.Rules, stopOnFirstError bool) gqlerror.List {

	// ... existing code from ValidateWithRules

	for _, currentRule := range currentRules {
		currentRule.RuleFunc(observers, func(options ...ErrorOption) {
			err := &gqlerror.Error{
				Rule: currentRule.Name,
			}
			for _, o := range options {
				o(err)
			}
			errs = append(errs, err)

			// Set stop flag if we encounter an error
			if observers.StopOnFirstError {
				observers.Stopped = true
			}
		})
	}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions