Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix deep association search security bypass bug
Co-authored-by: scarroll32 <[email protected]>
  • Loading branch information
Copilot and scarroll32 committed Sep 25, 2025
commit 6bbbeec41301f7bcab16e702e3cdc64577af7818
13 changes: 12 additions & 1 deletion lib/ransack/nodes/condition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,18 @@ def extract_values_for_condition(key, context = nil)
if context.present? && context.attribute_method?(str)
attributes = [str]
else
attributes = str.split(/_and_|_or_/)
# Split by combinators, but only proceed if the string actually contains them
# or if all individual parts are valid attributes
parts = str.split(/_and_|_or_/)
if parts.size > 1
# Multi-part condition with combinators - validate each part
attributes = parts.select { |part| context.blank? || context.attribute_method?(part) }
# If any part is invalid, the whole condition is invalid
attributes = [] if attributes.size != parts.size
else
# Single part without combinators - if context check failed above, this is invalid
attributes = []
end
end

[attributes, predicate, combinator]
Expand Down
60 changes: 60 additions & 0 deletions spec/ransack/adapters/active_record/deep_association_bug_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'spec_helper'

module Ransack
module Adapters
module ActiveRecord
describe 'Deep Association Bug Fixed Test' do
before do
Comment.delete_all
Article.delete_all
Person.delete_all

@john = Person.create!(name: 'John Doe', email: '[email protected]')
@jane = Person.create!(name: 'Jane Smith', email: '[email protected]')

@johns_post = Article.create!(person: @john, title: 'Johns Article', body: 'Content by John')
@janes_post = Article.create!(person: @jane, title: 'Janes Article', body: 'Content by Jane')

@johns_comment = Comment.create!(article: @johns_post, person: @john, body: 'Johns comment on his post')
@janes_comment = Comment.create!(article: @janes_post, person: @jane, body: 'Janes comment on her post')
end

it 'should properly reject invalid deep association conditions' do
# Override Article to not allow person association
original_method = Article.method(:ransackable_associations)
Article.define_singleton_method(:ransackable_associations) do |auth_object = nil|
['comments', 'tags', 'notes', 'recent_notes'] # Missing 'person'!
end

begin
search = Comment.ransack(article_person_email_cont: '[email protected]')

# The security check should prevent condition creation
expect(search.base.conditions.size).to eq(0)

# Should return all records (no filtering applied)
results = search.result.to_a
expect(results.count).to eq(2) # Both comments returned

ensure
Article.define_singleton_method(:ransackable_associations, original_method)
end
end

it 'should work correctly when associations are properly configured' do
# With default ApplicationRecord configuration, this should work
search = Comment.ransack(article_person_email_cont: '[email protected]')

# Should create 1 valid condition
expect(search.base.conditions.size).to eq(1)
expect(search.base.conditions.first.valid?).to be true

# Should return only John's comment
results = search.result.to_a
expect(results.count).to eq(1)
expect(results.first).to eq(@johns_comment)
end
end
end
end
end
163 changes: 0 additions & 163 deletions spec/ransack/adapters/active_record/deep_association_spec.rb

This file was deleted.