diff --git a/lib/brakeman/checks/check_unscoped_find.rb b/lib/brakeman/checks/check_unscoped_find.rb index fad71f8843..581c85e93d 100644 --- a/lib/brakeman/checks/check_unscoped_find.rb +++ b/lib/brakeman/checks/check_unscoped_find.rb @@ -11,7 +11,7 @@ def run_check associated_model_names = active_record_models.keys.select do |name| if belongs_to = active_record_models[name].associations[:belongs_to] - not optional_belongs_to? belongs_to + not self_referential_association? belongs_to, name else false end @@ -52,12 +52,16 @@ def process_result result :cwe_id => [285] end - def optional_belongs_to? exp + def self_referential_association? exp, name return false unless exp.is_a? Array exp.each do |e| if hash? e and true? hash_access(e, :optional) - return true + hash_iterate e do |key, value| + if key[1] == :class_name and name == value[1].to_sym + return true + end + end end end diff --git a/test/apps/rails7/app/controllers/groups_controller.rb b/test/apps/rails7/app/controllers/groups_controller.rb new file mode 100644 index 0000000000..2e0f51adf7 --- /dev/null +++ b/test/apps/rails7/app/controllers/groups_controller.rb @@ -0,0 +1,6 @@ +class GroupsController < ApplicationController + def show + @group = Group.find(params[:id]) + @user = User.find(params[:id]) + end +end diff --git a/test/apps/rails7/app/models/group.rb b/test/apps/rails7/app/models/group.rb new file mode 100644 index 0000000000..49e37063c1 --- /dev/null +++ b/test/apps/rails7/app/models/group.rb @@ -0,0 +1,3 @@ +class Group < ApplicationRecord + belongs_to :user, optional: true +end diff --git a/test/apps/rails7/app/models/user.rb b/test/apps/rails7/app/models/user.rb index 379658a509..065c6eb77a 100644 --- a/test/apps/rails7/app/models/user.rb +++ b/test/apps/rails7/app/models/user.rb @@ -1,2 +1,3 @@ class User < ApplicationRecord + belongs_to :matched_user, class_name: 'User', optional: true end diff --git a/test/tests/rails7.rb b/test/tests/rails7.rb index 915eb5911f..83fd9e019a 100644 --- a/test/tests/rails7.rb +++ b/test/tests/rails7.rb @@ -16,7 +16,7 @@ def expected :controller => 0, :model => 0, :template => 0, - :warning => 23 + :warning => 24 } end @@ -396,4 +396,32 @@ def test_redirect_back_or_to code: s(:call, nil, :redirect_back_or_to, s(:call, s(:params), :[], s(:lit, :x))), user_input: s(:call, s(:params), :[], s(:lit, :x)) end + + def test_unscoped_find + assert_warning check_name: "UnscopedFind", + type: :warning, + warning_code: 82, + fingerprint: "e84705527089566771bd3ae5b04f9c82529a0f388a4864eb4a91f7ad468541da", + warning_type: "Unscoped Find", + line: 3, + message: /^Unscoped\ call\ to\ `Group\#find`/, + confidence: 2, + relative_path: "app/controllers/groups_controller.rb", + code: s(:call, s(:const, :Group), :find, s(:call, s(:params), :[], s(:lit, :id))), + user_input: s(:call, s(:params), :[], s(:lit, :id)) + end + + def test_unscoped_find_2 + assert_no_warning check_name: "UnscopedFind", + type: :warning, + warning_code: 82, + fingerprint: "f2ba23dcceff3cefef2d9fd08a0fe9f87b5936226ec883a73e3a93629e172387", + warning_type: "Unscoped Find", + line: 4, + message: /^Unscoped\ call\ to\ `User\#find`/, + confidence: 2, + relative_path: "app/controllers/groups_controller.rb", + code: s(:call, s(:const, :User), :find, s(:call, s(:params), :[], s(:lit, :id))), + user_input: s(:call, s(:params), :[], s(:lit, :id)) + end end