CVE-2013-7224: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: Fat Free CRM before 0.12.1 does not restrict JSON serialization, which allows remote attackers to obtain sensitive information via a direct request, as demonstrated by a request for users/1.json.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
Published: 2014-01-02T14:59Z
Repository: https://github.com/fatfreecrm/fat_free_crm
Language: Ruby
Files changed: app/models/users/user.rb, config/routes.rb, spec/models/users/user_spec.rb, spec/routing/users_routing_spec.rb
Commit date: 2013-12-27 13:57:00 +0800
Commit message: Add custom serializers for xml and json.

Diff: diff --git a/app/models/users/user.rb b/app/models/users/user.rb
index 1d903796d..c4944bac1 100644
--- a/app/models/users/user.rb
+++ b/app/models/users/user.rb
@@ -145,10 +145,18 @@ class User < ActiveRecord::Base
   def group_ids=(value)
     value = value.join.split(',').map(&:to_i) if value.map{|v| v.to_s.include?(',')}.any?
     super(value)
   end
 
+  def to_json(options = nil)
+    [name].to_json
+  end
+
+  def to_xml(options = nil)
+    [name].to_xml
+  end
+
   private
 
   # Suspend newly created user if signup requires an approval.
   #----------------------------------------------------------------------------
   def check_if_needs_approval
diff --git a/config/routes.rb b/config/routes.rb
index aeb9234fe..933e3faf6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -135,11 +135,11 @@ Rails.application.routes.draw do
     member do
       put :complete
     end
   end
 
-  resources :users, :id => /\d+/ do
+  resources :users, :id => /\d+/, :except => [:index, :destroy] do
     member do
       get :avatar
       get :password
       put :upload_avatar
       put :change_password
diff --git a/spec/models/users/user_spec.rb b/spec/models/users/user_spec.rb
index dfc1294e5..2dd6149f2 100644
--- a/spec/models/users/user_spec.rb
+++ b/spec/models/users/user_spec.rb
@@ -207,6 +207,20 @@ describe User do
 
       @user.set_single_access_token
       @user.single_access_token.should == "token"
     end
   end
+
+  describe "serialization" do
+
+    let(:user) { FactoryGirl.build(:user) }
+
+    it "to json" do
+      expect(user.to_json).to eql([user.name].to_json)
+    end
+
+    it "to xml" do
+      expect(user.to_xml).to eql([user.name].to_xml)
+    end
+
+  end
 end
diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb
index 0c9ab8b0b..f54782ff2 100644
--- a/spec/routing/users_routing_spec.rb
+++ b/spec/routing/users_routing_spec.rb
@@ -6,12 +6,12 @@
 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
 
 describe UsersController do
   describe "routing" do
 
-    it "recognizes and generates #index" do
-      { :get => "/users" }.should route_to(:controller => "users", :action => "index")
+    it "doesn't recognize #index" do
+      { :get => "/users" }.should_not be_routable
     end
 
     it "recognizes and generates #new as /signup" do
       { :get => "/signup" }.should route_to(:controller => "users", :action => "new")
     end
@@ -38,12 +38,12 @@ describe UsersController do
 
     it "doesn't recognize #update with non-numeric id" do
       { :put => "/opportunities/aaron" }.should_not be_routable
     end
 
-    it "recognizes and generates #destroy" do
-      { :delete => "/users/1" }.should route_to(:controller => "users", :action => "destroy", :id => "1")
+    it "doesn't recognize #destroy" do
+      { :delete => "/users/1" }.should_not be_routable
     end
 
     it "doesn't recognize #destroy with non-numeric id" do
       { :delete => "/opportunities/aaron" }.should_not be_routable
     end
@@ -79,6 +79,5 @@ describe UsersController do
     it "doesn't recognize #change_password with non-numeric id" do
       { :put => "/opportunities/aaron/change_password" }.should_not be_routable
     end
   end
 end
-

Vulnerable code:   resources :users, :id => /\d+/ do
    it "recognizes and generates #index" do
      { :get => "/users" }.should route_to(:controller => "users", :action => "index")
    it "recognizes and generates #destroy" do
      { :delete => "/users/1" }.should route_to(:controller => "users", :action => "destroy", :id => "1")

Fixed code:   def to_json(options = nil)
    [name].to_json
  end

  def to_xml(options = nil)
    [name].to_xml
  end

  resources :users, :id => /\d+/, :except => [:index, :destroy] do

  describe "serialization" do

    let(:user) { FactoryGirl.build(:user) }

    it "to json" do
      expect(user.to_json).to eql([user.name].to_json)
    end

    it "to xml" do
      expect(user.to_xml).to eql([user.name].to_xml)
    end

  end
    it "doesn't recognize #index" do
      { :get => "/users" }.should_not be_routable
    it "doesn't recognize #destroy" do
      { :delete => "/users/1" }.should_not be_routable