CVE-2013-2506 (published 2013-03-08T18:55Z)

app/models/spree/user.rb in spree_auth_devise in Spree 1.1.x before 1.1.6, 1.2.x, and 1.3.x does not perform mass assignment safely when updating a user, which allows remote authenticated users to assign arbitrary roles to themselves.

Severity: MEDIUM
CVSS v2 base score: 4.0 (AV:N/AC:L/Au:S/C:N/I:P/A:N)

Weakness information:
cwe_id: CWE-264
cwe_name: Permissions, Privileges, and Access Controls
description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.

Fix information:
repo_url: https://github.com/spree/spree_auth_devise
commit_details: repo_url: https://github.com/spree/spree_auth_devise
author: John Dyer
author_date: 2013-02-22 10:13:12-05:00
msg: Remove Mass Assignment of Role IDs
repository: repo_url: https://github.com/spree/spree_auth_devise
repo_name: spree/spree_auth_devise
description: Provides authentication (user accounts, login & signup) for @spree by using Devise
repo_language: Ruby
owner: spree
file_changes: filename: users_controller.rb
change_type: ModificationType.MODIFY
diff: @@ -16,6 +16,47 @@ module Spree
         end
       end
 
+      def create
+        if params[:user]
+          roles = params[:user].delete("spree_role_ids")
+        end
+
+        @user = Spree::User.new(params[:user])
+        if @user.save
+
+          if roles
+            @user.spree_roles = roles.reject(&:blank?).collect{|r| Spree::Role.find(r)}
+          end
+
+          flash.now[:notice] = t(:created_successfully)
+          render :edit
+        else
+          render :new
+        end
+      end
+
+      def update
+        if params[:user]
+          roles = params[:user].delete("spree_role_ids")
+        end
+
+        if @user.update_attributes(params[:user])
+          if roles
+            @user.spree_roles = roles.reject(&:blank?).collect{|r| Spree::Role.find(r)}
+          end
+
+          if params[:user][:password].present?
+            # this logic needed b/c devise wants to log us out after password changes
+            user = Spree::User.reset_password_by_token(params[:user])
+            sign_in(@user, :event => :authentication, :bypass => !Spree::Auth::Config[:signout_after_password_change])
+          end
+          flash.now[:notice] = t(:account_updated)
+          render :edit
+        else
+          render :edit
+        end
+      end
+
       def generate_api_key
         if @user.generate_spree_api_key!
           flash.notice = t('key_generated', :scope => 'spree.api')

programming_language: Ruby
filename: user.rb
change_type: ModificationType.MODIFY
diff: @@ -14,7 +14,7 @@ module Spree
     before_destroy :check_completed_orders
 
     # Setup accessible (or protected) attributes for your model
-    attr_accessible :email, :password, :password_confirmation, :remember_me, :persistence_token, :login, :spree_role_ids
+    attr_accessible :email, :password, :password_confirmation, :remember_me, :persistence_token, :login
 
     users_table_name = User.table_name
     roles_table_name = Role.table_name

programming_language: Ruby
filename: users_controller_spec.rb
change_type: ModificationType.MODIFY
diff: @@ -3,6 +3,7 @@ require 'spec_helper'
 describe Spree::UsersController do
   let(:admin_user) { create(:user) }
   let(:user) { create(:user) }
+  let(:role) { create(:role) }
 
   before do
     controller.stub(:spree_current_user => user)
@@ -23,5 +24,9 @@ describe Spree::UsersController do
         response.should redirect_to(spree.account_url(:only_path => true))
       end
     end
+
+    it 'should not update roles' do
+      expect { spree_put :update, { :user => { :spree_role_ids => [role.id] } }}.to raise_exception(ActiveModel::MassAssignmentSecurity::Error)
+    end
   end
 end

programming_language: Ruby