Class: Scryer::Rules::GraphqlMissingQueryLimitsRule

Inherits:
Scryer::Rule
  • Object
show all
Defined in:
lib/scryer/rules/graphql_missing_query_limits_rule.rb

Overview

Flags a class X < GraphQL::Schema (or a class whose superclass constant path text is exactly GraphQL::Schema) whose body calls neither max_depth nor max_complexity anywhere — without at least one of those, a client can send an arbitrarily deep/expensive query and the server will try to resolve all of it, a common denial-of-service vector for GraphQL APIs. Both missing is flagged as a single finding per class (not one per missing directive), the same "did the class do the safe thing at all" pattern as ActiveStorageMissingContentTypeValidationRule/IdorRule.

Constant Summary collapse

LIMIT_METHODS =
%w[max_depth max_complexity].freeze

Instance Attribute Summary

Attributes inherited from Scryer::Rule

#file, #sexp, #source

Instance Method Summary collapse

Methods inherited from Scryer::Rule

inherited, #initialize

Constructor Details

This class inherits a constructor from Scryer::Rule

Instance Method Details

#scanObject



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/scryer/rules/graphql_missing_query_limits_rule.rb', line 20

def scan
  findings = []

  Ast.each_node(sexp) do |node|
    next unless Ast.tagged?(node, :class)

    superclass = superclass_name(node[2])
    next unless superclass == "GraphQL::Schema"

    body = node[3]
    next if each_call_names(body).any? { |name| LIMIT_METHODS.include?(name) }

    class_name = Ast.ident_text(node[1].is_a?(Array) ? node[1][1] : nil)
    line = Ast.line_of(node)
    findings << finding(
      line: line,
      message: "`#{class_name}` extends `GraphQL::Schema` but calls neither `max_depth` nor " \
                "`max_complexity` — without either limit, a client can send an arbitrarily " \
                "deep or expensive query and the server will attempt to resolve all of it, a " \
                "common denial-of-service vector for GraphQL APIs.",
      suggested_fix: "Add at least one limit to the schema, e.g. `max_depth 15` and/or " \
                      "`max_complexity 300` (tune both to what this API's real queries need)."
    )
  end

  findings
end