Moderate severityNVD Advisory· Published Nov 17, 2010· Updated Apr 29, 2026
CVE-2010-3978
CVE-2010-3978
Description
Spree 0.11.x before 0.11.2 and 0.30.x before 0.30.0 exchanges data using JavaScript Object Notation (JSON) without a mechanism for validating requests, which allows remote attackers to obtain sensitive information via vectors involving (1) admin/products.json, (2) admin/users.json, or (3) admin/overview/get_report_data, related to a "JSON hijacking" issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
spreeRubyGems | >= 0.11.0, < 0.11.2 | 0.11.2 |
spreeRubyGems | >= 0.30.0.beta1, < 0.30.0 | 0.30.0 |
Affected products
3cpe:2.3:a:spreecommerce:spree:0.11.0:*:*:*:*:*:*:*+ 2 more
- cpe:2.3:a:spreecommerce:spree:0.11.0:*:*:*:*:*:*:*
- cpe:2.3:a:spreecommerce:spree:0.11.1:*:*:*:*:*:*:*
- cpe:2.3:a:spreecommerce:spree:0.30.0:beta1:*:*:*:*:*:*
Patches
2d881b2bb610eSECURITY FIX: Do not allow GET access to JSON views without including CSRF token.
9 files changed · +23 −13
app/controllers/admin/overview_controller.rb+1 −1 modified@@ -8,7 +8,7 @@ def index #@users = User.find_with_deleted(:all, :order => 'updated_at desc') # going to list today's orders, yesterday's orders, older orders # have a filter / search at the top - # @orders, @ + # @orders, @ end end
app/controllers/admin/products_controller.rb+1 −0 modified@@ -1,5 +1,6 @@ class Admin::ProductsController < Admin::BaseController resource_controller + before_filter :check_json_authenticity, :only => :index before_filter :load_data, :except => :index index.response do |wants|
app/controllers/admin/users_controller.rb+2 −1 modified@@ -1,5 +1,6 @@ class Admin::UsersController < Admin::BaseController resource_controller + before_filter :check_json_authenticity, :only => :index before_filter :load_roles, :only => [:edit, :new, :update, :create] create.after :save_user_roles @@ -9,7 +10,7 @@ class Admin::UsersController < Admin::BaseController wants.html { render :action => :index } wants.json { render :json => @collection.to_json(:include => {:bill_address => {:include => [:state, :country]}, :ship_address => {:include => [:state, :country]}}) } end - + destroy.success.wants.js { render_js_for_destroy } private
app/controllers/spree/base_controller.rb+8 −2 modified@@ -59,14 +59,20 @@ def title protected + # Index request for JSON needs to pass a CSRF token in order to prevent JSON Hijacking + def check_json_authenticity + return unless request.format.js? or request.format.json? + form_authenticity_token == params[request_forgery_protection_token] || raise(ActionController::InvalidAuthenticityToken) + end + def default_title Spree::Config[:site_name] end - + def accurate_title return nil end - + def reject_unknown_object # workaround to catch problems with loading errors for permalink ids (reconsider RC permalink hack elsewhere?) begin
vendor/extensions/overview_dashboard/app/controllers/admin/overview_controller.rb+3 −1 modified@@ -1,6 +1,8 @@ # this clas was inspired (heavily) from the mephisto admin architecture class Admin::OverviewController < Admin::BaseController + before_filter :check_json_authenticity, :only => :get_report_data + #todo, add rss feed of information that is happening def index @@ -57,7 +59,7 @@ def conditions(params) ["completed_at >= ?", params[:from]] end end - + def fill_empty_entries(orders, params) from_date = params[:from].to_date to_date = (params[:to] || Time.now).to_date
vendor/extensions/overview_dashboard/public/javascripts/dashboard.js+4 −4 modified@@ -95,15 +95,15 @@ jQuery(document).ready(function(){ jQuery.ajax({ type: 'GET', - url: 'admin/overview/get_report_data', - data: ({report: 'orders_by_day', name: report, value: value, authenticity_token: AUTH_TOKEN}), + url: 'admin/overview/get_report_data?authenticity_token=' + AUTH_TOKEN, + data: ({report: 'orders_by_day', name: report, value: value}), success: handle_orders_by_day }); jQuery.ajax({ type: 'GET', - url: 'admin/overview/get_report_data', - data: ({report: 'orders_totals', name: report, authenticity_token: AUTH_TOKEN}), + url: 'admin/overview/get_report_data?authenticity_token=' + AUTH_TOKEN, + data: ({report: 'orders_totals', name: report}), success: handle_orders_total });
vendor/extensions/theme_default/app/views/shared/_admin_head.html.erb+2 −2 modified@@ -8,7 +8,7 @@ <%= javascript_include_tag('jquery.template') unless controller.controller_name == "overview" %> <%= javascript_include_tag 'spree', 'nested-attribute', 'zone', 'calculator', 'gateway' %> <%= javascript_tag "$ = jQuery;" %> -<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> +<%= javascript_tag "var AUTH_TOKEN = encodeURIComponent(#{form_authenticity_token.inspect});" %> <%= javascript_include_tag 'jquery.alerts/jquery.alerts.js' %> <%= javascript_include_tag 'jquery.autocomplete.min.js' %> @@ -17,5 +17,5 @@ <%= stylesheet_link_tag 'jquery.autocomplete.css' %> <%= javascript_tag "jQuery.alerts.dialogClass = 'spree';" %> -<%= unobtrusive_datepicker_includes %> +<%= unobtrusive_datepicker_includes %> <%= yield :head %>
vendor/extensions/theme_default/public/javascripts/admin/checkouts/edit.js+1 −1 modified@@ -40,7 +40,7 @@ jQuery(document).ready(function(){ }); } - $("#customer_search").autocomplete("/admin/users.json", { + $("#customer_search").autocomplete("/admin/users.json?authenticity_token=" + AUTH_TOKEN, { minChars: 5, delay: 1500, parse: prep_autocomplete_data,
vendor/extensions/theme_default/public/javascripts/admin/orders/edit.js+1 −1 modified@@ -75,7 +75,7 @@ jQuery(document).ready(function(){ }); } - $("#add_product_name").autocomplete("/admin/products.json", { + $("#add_product_name").autocomplete("/admin/products.json?authenticity_token=" + AUTH_TOKEN, { parse: prep_autocomplete_data, formatItem: function(item) { return format_autocomplete(item);
19944bd999c3SECURITY FIX: Do not allow access to REST API without valid token in request header.
1 file changed · +2 −3
vendor/extensions/api/app/controllers/api/base_controller.rb+2 −3 modified@@ -25,9 +25,8 @@ def self.resource_controller_for_api define_method :admin_token_passed_in_headers do token = request.headers['X-SpreeAPIKey'] - return false unless token - @current_user = User.find_by_api_key(token) - @current_user.has_role? 'admin' + return access_denied unless token + return access_denied unless @current_user = User.find_by_api_key(token) end define_method :end_of_association_chain do
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
16- spreecommerce.com/blog/2010/11/09/spree-0-30-0-released/nvdPatch
- github.com/railsdog/spree/commit/19944bd999c310d9b10d16a41f48ebac97dc4facnvdExploitWEB
- github.com/advisories/GHSA-hwrx-wc75-mgh7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2010-3978ghsaADVISORY
- spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerabilityghsaWEB
- spreecommerce.com/blog/2010/11/09/spree-0-30-0-releasedghsaWEB
- twitter.com/conviso/statuses/29555076248nvdWEB
- www.conviso.com.br/json-hijacking-vulnerabilityghsaWEB
- www.conviso.com.br/security-advisory-spree-e-commerce-json-v-0-11xghsaWEB
- www.securityfocus.com/archive/1/514674/100/0/threadednvdWEB
- github.com/railsdog/spree/commit/d881b2bb610ea33e2364ff16feb8e702dfeda135nvdWEB
- github.com/rubysec/ruby-advisory-db/blob/master/gems/spree/CVE-2010-3978.ymlghsaWEB
- spreecommerce.com/blog/json-hijacking-vulnerabilityghsaWEB
- spreecommerce.com/blog/2010/11/02/json-hijacking-vulnerability/nvd
- www.conviso.com.br/json-hijacking-vulnerability/nvd
- www.conviso.com.br/security-advisory-spree-e-commerce-json-v-0-11x/nvd
News mentions
0No linked articles in our index yet.