Class: Scryer::Rules::MissingAuthorizationRule
- Inherits:
-
Scryer::Rule
- Object
- Scryer::Rule
- Scryer::Rules::MissingAuthorizationRule
- Defined in:
- lib/scryer/rules/missing_authorization_rule.rb
Overview
Flags a *Controller class that defines create/update/destroy
(Rails' three standard write actions) with NO authorization evidence
anywhere in the class — broader than IdorRule, which only fires when
there's also a params-derived Model.find call in the same class.
Plenty of write actions don't call .find at all (Model.create(...)
needs no lookup; a destroy might act on an object set up in a
before_action), so IdorRule's narrower pattern misses them even
though "this write action has no visible authorization check at all"
is exactly as real a concern. Restricted to the three standard write
actions (not every public method) specifically to avoid flagging
genuinely public controllers (a marketing page, a login form) that
have no write actions at all and legitimately need no authorization —
a controller that defines create/update/destroy at all is
already a much stronger "this manages a real resource" signal than
any action name would be.
Expect overlap with idor on controllers that both .find a record
AND have no authorization — that's two different rules independently
confirming the same underlying gap from two different code shapes
(a lookup vs. a write action), not double-counting a bug.
Constant Summary collapse
- WRITE_ACTIONS =
%w[create update destroy].freeze
- AUTHORIZATION_METHODS =
Duplicated from IdorRule intentionally, same as NON_MODEL_RECEIVERS is duplicated between IdorRule and MassAssignmentRule — a small, stable list not worth a shared-module indirection for two callers.
%w[ authorize authorize! policy_scope can? cannot? load_and_authorize_resource authorize_resource verify_authorized verify_policy_scoped ].freeze
Instance Attribute Summary
Attributes inherited from Scryer::Rule
Instance Method Summary collapse
Methods inherited from Scryer::Rule
Constructor Details
This class inherits a constructor from Scryer::Rule
Instance Method Details
#scan ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/scryer/rules/missing_authorization_rule.rb', line 43 def scan findings = [] Ast.each_node(sexp) do |node| next unless Ast.tagged?(node, :class) class_name = Ast.class_name(node[1]) next unless class_name.to_s.end_with?("Controller") body = node[3] next if each_call_names(body).any? { |name| AUTHORIZATION_METHODS.include?(name) } each_write_action_def(body).each do |def_node, action_name| findings << finding( line: Ast.line_of(def_node), message: "`#{class_name}##{action_name}` writes data (a standard Rails write " \ "action), and `#{class_name}` has no visible authorization check anywhere " \ "in it (no `authorize`, `policy_scope`, `can?`/`cannot?`, or CanCanCan/" \ "Pundit callback) — any logged-in (or, if this controller skips " \ "authentication too, any) user may be able to call this action.", suggested_fix: "Add an explicit authorization check before the write happens — " \ "`authorize @thing` (Pundit) or `authorize! :#{action_name}, @thing` " \ "(CanCanCan) — or `load_and_authorize_resource`/`after_action " \ ":verify_authorized` at the class level if every action here should " \ "be gated the same way." ) end end findings end |