Skip to content

Commit

Permalink
Vulnerability fix: validate return_to param using request.host (#3627)
Browse files Browse the repository at this point in the history
* Use starts_with?

Add specs

* Fix linter issues

* Fix linter issues. Disable metric ClassLength cop on config file.

* Use base_url to check return_to param

* Fix linter issues

* Consider redirect to paths. Fix linter issues.

* Address feedback

---------

Co-authored-by: Steven Chau <[email protected]>
  • Loading branch information
nicoayala and whereisciao authored Jul 1, 2023
1 parent f06df8f commit da48004
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
6 changes: 5 additions & 1 deletion app/controllers/rails_admin/main_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ def respond_to_missing?(sym, include_private)
end

def back_or_index
params[:return_to].presence && params[:return_to].include?(request.host) && (params[:return_to] != request.fullpath) ? params[:return_to] : index_path
allowed_return_to?(params[:return_to].to_s) ? params[:return_to] : index_path
end

def allowed_return_to?(url)
url != request.fullpath && url.start_with?(request.base_url, '/') && !url.start_with?('//')
end

def get_sort_hash(model_config)
Expand Down
66 changes: 66 additions & 0 deletions spec/controllers/rails_admin/main_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -470,4 +470,70 @@ def get(action, params)
)
end
end

describe 'back_or_index' do
before do
allow(controller).to receive(:index_path).and_return(index_path)
end

let(:index_path) { '/' }

it 'returns back to index when return_to is not defined' do
controller.params = {}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to return_to url when it starts with same protocol and host' do
return_to_url = "http://#{request.host}/teams"
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(return_to_url)
end

it 'returns back to return_to url when it contains a path' do
return_to_url = '/teams'
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(return_to_url)
end

it 'returns back to index path when return_to path does not start with slash' do
return_to_url = 'teams'
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to url does not start with full protocol' do
return_to_url = "#{request.host}/teams"
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to url starts with double slash' do
return_to_url = "//#{request.host}/teams"
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to url starts with tripple slash' do
return_to_url = "///#{request.host}/teams"
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to url does not have host' do
return_to_url = 'http:///teams'
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to url starts with different protocol' do
return_to_url = "other://#{request.host}/teams"
controller.params = {return_to: return_to_url}
expect(controller.send(:back_or_index)).to eq(index_path)
end

it 'returns back to index path when return_to does not start with the same protocol and host' do
controller.params = {return_to: "http://google.com?#{request.host}"}
expect(controller.send(:back_or_index)).to eq(index_path)
end
end
end

0 comments on commit da48004

Please sign in to comment.