From 4d0981b1bff770a107aef3aa6345a33cfed1b83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?= Date: Wed, 6 Aug 2014 21:17:19 -0300 Subject: [PATCH] Check attributes passed to create_with and where If the request parameters are passed to create_with and where they can be used to do mass assignment when used in combination with Relation#create. Fixes CVE-2014-3514 --- .../forbidden_attributes_protection.rb | 1 + .../lib/active_record/relation/query_methods.rb | 16 ++++++++++-- .../cases/forbidden_attributes_protection_test.rb | 30 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/active_record/relation/query_methods.rb b/lib/active_record/relation/query_methods.rb index 72d3917..acf2f35 100644 --- a/lib/active_record/relation/query_methods.rb +++ b/lib/active_record/relation/query_methods.rb @@ -1,9 +1,12 @@ require 'active_support/core_ext/array/wrap' +require 'active_model/forbidden_attributes_protection' module ActiveRecord module QueryMethods extend ActiveSupport::Concern + include ActiveModel::ForbiddenAttributesProtection + # WhereChain objects act as placeholder for queries in which #where does not have any parameter. # In this case, #where must be chained with #not to return a new relation. class WhereChain @@ -540,7 +543,10 @@ module ActiveRecord if opts == :chain WhereChain.new(self) else - references!(PredicateBuilder.references(opts)) if Hash === opts + if Hash === opts + opts = sanitize_for_mass_assignment(opts) + references!(PredicateBuilder.references(opts)) + end self.where_values += build_where(opts, rest) self @@ -679,7 +685,13 @@ module ActiveRecord end def create_with!(value) # :nodoc: - self.create_with_value = value ? create_with_value.merge(value) : {} + if value + value = sanitize_for_mass_assignment(value) + self.create_with_value = create_with_value.merge(value) + else + self.create_with_value = {} + end + self end diff --git a/test/cases/forbidden_attributes_protection_test.rb b/test/cases/forbidden_attributes_protection_test.rb index 490b599..d3273e2 100644 --- a/test/cases/forbidden_attributes_protection_test.rb +++ b/test/cases/forbidden_attributes_protection_test.rb @@ -61,4 +61,34 @@ class ForbiddenAttributesProtectionTest < ActiveRecord::TestCase assert_equal 'Guille', person.first_name assert_equal 'm', person.gender end + + def test_create_with_checks_permitted + params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + + assert_raises(ActiveModel::ForbiddenAttributesError) do + Person.create_with(params).create! + end + end + + def test_create_with_works_with_params_values + params = ProtectedParams.new(first_name: 'Guille') + + person = Person.create_with(first_name: params[:first_name]).create! + assert_equal 'Guille', person.first_name + end + + def test_where_checks_permitted + params = ProtectedParams.new(first_name: 'Guille', gender: 'm') + + assert_raises(ActiveModel::ForbiddenAttributesError) do + Person.where(params).create! + end + end + + def test_where_works_with_params_values + params = ProtectedParams.new(first_name: 'Guille') + + person = Person.where(first_name: params[:first_name]).create! + assert_equal 'Guille', person.first_name + end end