Class: Scryer::Rules::CorsMisconfigurationRule

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

Overview

Flags the well-known Rack::Cors antipattern: a wildcard origin (origins '*') combined with credentials: true on a resource call. Per the CORS spec, browsers reject this combination in practice, but it's still the standard misconfiguration flagged in security reviews — either half alone (wildcard origin with no credentials, or credentials with a real origin allowlist) is fine.

Scoped per allow do ... end block (Rack::Cors' own grouping construct — each allow block gets its own origins/resource pairing), not file-wide: a common, legitimate pattern is a public, unauthenticated API in one allow block (origins '*', no credentials) and a separate authenticated partner API in another allow block in the same initializer (a real origin allowlist + credentials: true) — neither block alone is a misconfiguration, but an earlier file-wide "does '*' appear ANYWHERE AND does credentials: true appear ANYWHERE" check would flag the second block just because the first one happens to use a wildcard. Requiring both signals to come from the same allow block's own subtree fixes that without losing detection of the real antipattern (both signals still just need to appear somewhere within one block, not literally on the same resource call, since origins and resource are usually sibling statements in the same block rather than one call).

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



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/scryer/rules/cors_misconfiguration_rule.rb', line 34

def scan
  findings = []

  allow_blocks(sexp).each do |block|
    next unless wildcard_origin_anywhere?(block)

    each_credentialed_resource(block).each do |node|
      findings << finding(
        line: Ast.line_of(node),
        message: "This `allow` block sets a wildcard origin (`origins '*'`) and this " \
                  "`resource` call sets `credentials: true` — browsers won't honor that " \
                  "combination for actual credentialed requests, and Rack::Cors handling it " \
                  "inconsistently is the standard CORS misconfiguration flagged in reviews. " \
                  "Either restrict origins to a real allowlist, or drop `credentials: true`.",
        suggested_fix: "Replace the wildcard with an explicit origin allowlist wherever " \
                        "`credentials: true` is set: `origins 'https://app.example.com'` " \
                        "instead of `origins '*'` — a wildcard origin should only be paired " \
                        "with `credentials: false` (the default)."
      )
    end
  end

  findings
end