[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] [CVE-2016-0753] Possible Input Validation Circumvention in Active Model
From:       Aaron Patterson <tenderlove () ruby-lang ! org>
Date:       2016-01-25 19:37:57
Message-ID: 20160125193757.GG14069 () TC ! local
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


Possible Input Validation Circumvention in Active Model

There is a possible input validation circumvention vulnerability in Active
Model. This vulnerability has been assigned the CVE identifier CVE-2016-0753.

Versions Affected:  4.1.0 and newer
Not affected:       4.0.13 and older
Fixed Versions:     5.0.0.beta1.1, 4.2.5.1, 4.1.14.1

Impact
------
Code that uses Active Model based models (including Active Record models) and
does not validate user input before passing it to the model can be subject to
an attack where specially crafted input will cause the model to skip
validations.

Vulnerable code will look something like this:

```ruby
SomeModel.new(unverified_user_input)
```

Rails users using Strong Parameters are generally not impacted by this issue
as they are encouraged to whitelist parameters and must specifically opt-out
of input verification using the `permit!` method to allow mass assignment.

For example, a vulnerable Rails application will have code that looks like
this:

```ruby
def create
  params.permit! # allow all parameters
  @user = User.new params[:users]
end
```

Active Model and Active Record objects are not equipped to handle arbitrary
user input.  It is up to the application to verify input before passing it to
Active Model models.  Rails users already have Strong Parameters in place to
handle white listing, but applications using Active Model and Active Record
outside of a Rails environment may be impacted.

All users running an affected release should either upgrade or use one of the
workarounds immediately.

Releases
--------
The FIXED releases are available at the normal locations.

Workarounds
-----------
There are several workarounds depending on the application.  Inside a Rails
application, stop using `permit!`.  Outside a Rails application, either use
Hash#slice to select the parameters you need, or integrate Strong Parameters
with your application.

Patches
-------
To aid users who aren't able to upgrade immediately we have provided patches for
the two supported release series. They are in git-am format and consist of a
single changeset.

* 4-1-validation_skip.patch - Patch for 4.1 series
* 4-2-validation_skip.patch - Patch for 4.2 series
* 5-0-validation_skip.patch - Patch for 5.0 series

Please note that only the 4.1.x and 4.2.x series are supported at present. Users
of earlier unsupported releases are advised to upgrade as soon as possible as we
cannot guarantee the continued availability of security fixes for unsupported
releases.

Credits
-------
Thanks to:

[John Backus](https://github.com/backus) from BlockScore for reporting this!

-- 
Aaron Patterson
http://tenderlovemaking.com/

["4-1-validation_skip.patch" (text/plain)]

From 7a01874b75fdd62ab3626490cdf1c65c0ba659d0 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@gmail.com>
Date: Mon, 18 Jan 2016 13:51:02 -0800
Subject: [PATCH] Eliminate instance level writers for class accessors

Instance level writers can have an impact on how the Active Model /
Record objects are saved.  Specifically, they can be used to bypass
validations.  This is a problem if mass assignment protection is
disabled and specific attributes are passed to the constructor.

Conflicts:
	activerecord/lib/active_record/scoping/default.rb
	activesupport/lib/active_support/callbacks.rb

CVE-2016-0753
---
 activemodel/lib/active_model/serializers/json.rb | 2 +-
 activemodel/lib/active_model/validations.rb      | 3 ++-
 activerecord/lib/active_record/enum.rb           | 2 +-
 activerecord/lib/active_record/reflection.rb     | 4 ++--
 activesupport/lib/active_support/callbacks.rb    | 2 +-
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb
index c58e73f..fd405ff 100644
--- a/activemodel/lib/active_model/serializers/json.rb
+++ b/activemodel/lib/active_model/serializers/json.rb
@@ -10,7 +10,7 @@ module ActiveModel
       included do
         extend ActiveModel::Naming
 
-        class_attribute :include_root_in_json
+        class_attribute :include_root_in_json, instance_writer: false
         self.include_root_in_json = false
       end
 
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index e9674d5..7451da0 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -46,9 +46,10 @@ module ActiveModel
       include HelperMethods
 
       attr_accessor :validation_context
+      private :validation_context=
       define_callbacks :validate, scope: :name
 
-      class_attribute :_validators
+      class_attribute :_validators, instance_writer: false
       self._validators = Hash.new { |h,k| h[k] = [] }
     end
 
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index fba7747..c99941e 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -68,7 +68,7 @@ module ActiveRecord
   # Where conditions on an enum attribute must use the ordinal value of an enum.
   module Enum
     def self.extended(base) # :nodoc:
-      base.class_attribute(:defined_enums)
+      base.class_attribute(:defined_enums, instance_writer: false)
       base.defined_enums = {}
     end
 
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 824e005..82b0123 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -4,8 +4,8 @@ module ActiveRecord
     extend ActiveSupport::Concern
 
     included do
-      class_attribute :_reflections
-      class_attribute :aggregate_reflections
+      class_attribute :_reflections, instance_writer: false
+      class_attribute :aggregate_reflections, instance_writer: false
       self._reflections = {}
       self.aggregate_reflections = {}
     end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 3265d11..3ba690b 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -768,7 +768,7 @@ module ActiveSupport
         end
 
         names.each do |name|
-          class_attribute "_#{name}_callbacks"
+          class_attribute "_#{name}_callbacks", instance_writer: false
           set_callbacks name, CallbackChain.new(name, options)
         end
       end
-- 
2.2.1


["4-2-validation_skip.patch" (text/plain)]

From 4b6ca16fa865ce614beda503d7ff2a9a33a792ce Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@gmail.com>
Date: Mon, 18 Jan 2016 13:51:02 -0800
Subject: [PATCH] Eliminate instance level writers for class accessors

Instance level writers can have an impact on how the Active Model /
Record objects are saved.  Specifically, they can be used to bypass
validations.  This is a problem if mass assignment protection is
disabled and specific attributes are passed to the constructor.

Conflicts:
	activerecord/lib/active_record/scoping/default.rb
	activesupport/lib/active_support/callbacks.rb

CVE-2016-0753
---
 activemodel/lib/active_model/serializers/json.rb | 2 +-
 activemodel/lib/active_model/validations.rb      | 3 ++-
 activerecord/lib/active_record/enum.rb           | 2 +-
 activerecord/lib/active_record/reflection.rb     | 4 ++--
 activesupport/lib/active_support/callbacks.rb    | 2 +-
 5 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb
index b66dbf1..b64a829 100644
--- a/activemodel/lib/active_model/serializers/json.rb
+++ b/activemodel/lib/active_model/serializers/json.rb
@@ -10,7 +10,7 @@ module ActiveModel
       included do
         extend ActiveModel::Naming
 
-        class_attribute :include_root_in_json
+        class_attribute :include_root_in_json, instance_writer: false
         self.include_root_in_json = false
       end
 
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index e23b305..8185154 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -47,9 +47,10 @@ module ActiveModel
       include HelperMethods
 
       attr_accessor :validation_context
+      private :validation_context=
       define_callbacks :validate, scope: :name
 
-      class_attribute :_validators
+      class_attribute :_validators, instance_writer: false
       self._validators = Hash.new { |h,k| h[k] = [] }
     end
 
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 1df779e..7887991 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -69,7 +69,7 @@ module ActiveRecord
   # Where conditions on an enum attribute must use the ordinal value of an enum.
   module Enum
     def self.extended(base) # :nodoc:
-      base.class_attribute(:defined_enums)
+      base.class_attribute(:defined_enums, instance_writer: false)
       base.defined_enums = {}
     end
 
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 590bd6c..b46df26 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -7,8 +7,8 @@ module ActiveRecord
     extend ActiveSupport::Concern
 
     included do
-      class_attribute :_reflections
-      class_attribute :aggregate_reflections
+      class_attribute :_reflections, instance_writer: false
+      class_attribute :aggregate_reflections, instance_writer: false
       self._reflections = {}
       self.aggregate_reflections = {}
     end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 355cedb..98fd6b5 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -770,7 +770,7 @@ module ActiveSupport
         options = names.extract_options!
 
         names.each do |name|
-          class_attribute "_#{name}_callbacks"
+          class_attribute "_#{name}_callbacks", instance_writer: false
           set_callbacks name, CallbackChain.new(name, options)
 
           module_eval <<-RUBY, __FILE__, __LINE__ + 1
-- 
2.2.1


["5-0-validation_skip.patch" (text/plain)]

From a52175f55fc11a28521e0c4a86d80f545e5b0d68 Mon Sep 17 00:00:00 2001
From: Aaron Patterson <aaron.patterson@gmail.com>
Date: Mon, 18 Jan 2016 13:51:02 -0800
Subject: [PATCH] Eliminate instance level writers for class accessors

Instance level writers can have an impact on how the Active Model /
Record objects are saved.  Specifically, they can be used to bypass
validations.  This is a problem if mass assignment protection is
disabled and specific attributes are passed to the constructor.

CVE-2016-0753
---
 activemodel/lib/active_model/serializers/json.rb  | 2 +-
 activemodel/lib/active_model/validations.rb       | 3 ++-
 activerecord/lib/active_record/enum.rb            | 2 +-
 activerecord/lib/active_record/reflection.rb      | 4 ++--
 activerecord/lib/active_record/scoping/default.rb | 2 +-
 activesupport/lib/active_support/callbacks.rb     | 4 ++--
 6 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb
index b66dbf1..b64a829 100644
--- a/activemodel/lib/active_model/serializers/json.rb
+++ b/activemodel/lib/active_model/serializers/json.rb
@@ -10,7 +10,7 @@ module ActiveModel
       included do
         extend ActiveModel::Naming
 
-        class_attribute :include_root_in_json
+        class_attribute :include_root_in_json, instance_writer: false
         self.include_root_in_json = false
       end
 
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index f23c920..8159b9b 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -47,9 +47,10 @@ module ActiveModel
       include HelperMethods
 
       attr_accessor :validation_context
+      private :validation_context=
       define_callbacks :validate, scope: :name
 
-      class_attribute :_validators
+      class_attribute :_validators, instance_writer: false
       self._validators = Hash.new { |h,k| h[k] = [] }
     end
 
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 8655f68..311f8e1 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -95,7 +95,7 @@ module ActiveRecord
 
   module Enum
     def self.extended(base) # :nodoc:
-      base.class_attribute(:defined_enums)
+      base.class_attribute(:defined_enums, instance_writer: false)
       base.defined_enums = {}
     end
 
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 37e1862..320ced5 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -7,8 +7,8 @@ module ActiveRecord
     extend ActiveSupport::Concern
 
     included do
-      class_attribute :_reflections
-      class_attribute :aggregate_reflections
+      class_attribute :_reflections, instance_writer: false
+      class_attribute :aggregate_reflections, instance_writer: false
       self._reflections = {}
       self.aggregate_reflections = {}
     end
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index 8baf3b8..f6b6768 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -6,7 +6,7 @@ module ActiveRecord
       included do
         # Stores the default scope for the class.
         class_attribute :default_scopes, instance_writer: false, instance_predicate: false
-        class_attribute :default_scope_override, instance_predicate: false
+        class_attribute :default_scope_override, instance_writer: false, instance_predicate: false
 
         self.default_scopes = []
         self.default_scope_override = nil
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index bf560ec..e6baddf 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -71,7 +71,7 @@ module ActiveSupport
     # halt the entire callback chain and display a deprecation message.
     # If false, callback chains will only be halted by calling +throw :abort+.
     # Defaults to +true+.
-    mattr_accessor(:halt_and_display_warning_on_return_false) { true }
+    mattr_accessor(:halt_and_display_warning_on_return_false, instance_writer: false) { true }
 
     # Runs the callbacks for the given event.
     #
@@ -742,7 +742,7 @@ module ActiveSupport
         options = names.extract_options!
 
         names.each do |name|
-          class_attribute "_#{name}_callbacks"
+          class_attribute "_#{name}_callbacks", instance_writer: false
           set_callbacks name, CallbackChain.new(name, options)
 
           module_eval <<-RUBY, __FILE__, __LINE__ + 1
-- 
2.2.1


[Attachment #8 (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic