VYPR
High severityNVD Advisory· Published Feb 6, 2026· Updated Feb 9, 2026

Unauthenticated Spree Commerce users can view completed guest orders by Order ID

CVE-2026-25757

Description

Spree is an open source e-commerce solution built with Ruby on Rails. Prior to versions 5.0.8, 5.1.10, 5.2.7, and 5.3.2, unauthenticated users can view completed guest orders by Order ID. This issue may lead to disclosure of PII of guest users (including names, addresses and phone numbers). This issue has been patched in versions 5.0.8, 5.1.10, 5.2.7, and 5.3.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
spree_storefrontRubyGems
< 5.0.85.0.8
spree_storefrontRubyGems
>= 5.1.0, < 5.1.105.1.10
spree_storefrontRubyGems
>= 5.2.0, < 5.2.75.2.7
spree_storefrontRubyGems
>= 5.3.0, < 5.3.25.3.2

Affected products

1

Patches

4
3e00be64c128

Merge commit from fork

https://github.com/spree/spreeDamian LegawiecFeb 5, 2026via ghsa
4 files changed · +27 12
  • storefront/app/controllers/spree/orders_controller.rb+9 5 modified
    @@ -10,11 +10,17 @@ class OrdersController < StoreController
     
         before_action :assign_order_with_lock, only: :update
     
    +    rescue_from CanCan::AccessDenied do |exception|
    +      raise ActiveRecord::RecordNotFound
    +    end
    +
         # GET /orders/:id
         def show
           @order = complete_order_finder.new(number: params[:id], token: params[:token], store: current_store).execute.first
     
    -      raise ActiveRecord::RecordNotFound if @order.blank? || !authorize_access
    +      raise ActiveRecord::RecordNotFound if @order.blank?
    +
    +      authorize! :show, @order, params[:token]
     
           @shipments = @order.shipments.includes(:stock_location, :address, selected_shipping_rate: :shipping_method, inventory_units: :line_item)
         end
    @@ -49,9 +55,7 @@ def edit
         private
     
         def authorize_access
    -      return true if @order.user_id.nil?
    -
    -      @order.user == try_spree_current_user
    +      authorize! :show, @order, params[:token]
         end
     
         def find_order_by_cookie
    @@ -65,7 +69,7 @@ def find_order_by_cookie
         end
     
         def accurate_title
    -      if action_name == 'edit' || action_name == 'update'
    +      if ['edit', 'update'].include?(action_name)
             Spree.t(:shopping_cart)
           else
             Spree.t(:order_number, number: @order&.number)
    
  • storefront/app/controllers/spree/order_status_controller.rb+1 1 modified
    @@ -7,7 +7,7 @@ def new; end
         # validate email/order number and redirect to order page
         # POST /order_status
         def create
    -      raise ActiveRecord::RecordNotFound if params[:number].blank?
    +      raise ActiveRecord::RecordNotFound if params[:number].blank? || params[:email].blank?
     
           @order = order_finder.new(number: params[:number], email: params[:email], store: current_store).execute.first
     
    
  • storefront/spec/controllers/spree/orders_controller_spec.rb+9 6 modified
    @@ -105,7 +105,8 @@
       end
     
       describe '#show' do
    -    let(:order) { create(:completed_order_with_totals, store: store, user: user) }
    +    let(:order) { create(:completed_order_with_totals, store: store) }
    +    let(:user) { nil }
     
         it 'renders the show template' do
           get :show, params: { id: order.number, token: order.token }
    @@ -120,13 +121,15 @@
           end
         end
     
    -    context 'when order belongs to another user' do
    -      let(:order) { create(:completed_order_with_totals, store: store, user: create(:user)) }
    +    context 'when token is invalid' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect { get :show, params: { id: order.number, token: 'invalid' } }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
     
    +    context 'when token is missing' do
           it 'raises ActiveRecord::RecordNotFound' do
    -        expect do
    -          get :show, params: { id: order.number, token: order.token }
    -        end.to raise_error(ActiveRecord::RecordNotFound)
    +        expect { get :show, params: { id: order.number, token: '' } }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
       end
    
  • storefront/spec/controllers/spree/order_status_controller_spec.rb+8 0 modified
    @@ -64,5 +64,13 @@
             }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
    +
    +    context 'with blank email' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect {
    +          post :create, params: { number: order.number, email: '' }
    +        }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
       end
     end
    
6f6b8a7a28a8

Merge commit from fork

https://github.com/spree/spreeDamian LegawiecFeb 5, 2026via ghsa
4 files changed · +27 12
  • storefront/app/controllers/spree/orders_controller.rb+9 5 modified
    @@ -10,11 +10,17 @@ class OrdersController < StoreController
     
         before_action :assign_order_with_lock, only: :update
     
    +    rescue_from CanCan::AccessDenied do |exception|
    +      raise ActiveRecord::RecordNotFound
    +    end
    +
         # GET /orders/:id
         def show
           @order = complete_order_finder.new(number: params[:id], token: params[:token], store: current_store).execute.first
     
    -      raise ActiveRecord::RecordNotFound if @order.blank? || !authorize_access
    +      raise ActiveRecord::RecordNotFound if @order.blank?
    +
    +      authorize! :show, @order, params[:token]
     
           @shipments = @order.shipments.includes(:stock_location, :address, selected_shipping_rate: :shipping_method, inventory_units: :line_item)
         end
    @@ -49,9 +55,7 @@ def edit
         private
     
         def authorize_access
    -      return true if @order.user_id.nil?
    -
    -      @order.user == try_spree_current_user
    +      authorize! :show, @order, params[:token]
         end
     
         def find_order_by_cookie
    @@ -65,7 +69,7 @@ def find_order_by_cookie
         end
     
         def accurate_title
    -      if action_name == 'edit' || action_name == 'update'
    +      if ['edit', 'update'].include?(action_name)
             Spree.t(:shopping_cart)
           else
             Spree.t(:order_number, number: @order&.number)
    
  • storefront/app/controllers/spree/order_status_controller.rb+1 1 modified
    @@ -7,7 +7,7 @@ def new; end
         # validate email/order number and redirect to order page
         # POST /order_status
         def create
    -      raise ActiveRecord::RecordNotFound if params[:number].blank?
    +      raise ActiveRecord::RecordNotFound if params[:number].blank? || params[:email].blank?
     
           @order = order_finder.new(number: params[:number], email: params[:email], store: current_store).execute.first
     
    
  • storefront/spec/controllers/spree/orders_controller_spec.rb+9 6 modified
    @@ -105,7 +105,8 @@
       end
     
       describe '#show' do
    -    let(:order) { create(:completed_order_with_totals, store: store, user: user) }
    +    let(:order) { create(:completed_order_with_totals, store: store) }
    +    let(:user) { nil }
     
         it 'renders the show template' do
           get :show, params: { id: order.number, token: order.token }
    @@ -144,13 +145,15 @@
           end
         end
     
    -    context 'when order belongs to another user' do
    -      let(:order) { create(:completed_order_with_totals, store: store, user: create(:user)) }
    +    context 'when token is invalid' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect { get :show, params: { id: order.number, token: 'invalid' } }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
     
    +    context 'when token is missing' do
           it 'raises ActiveRecord::RecordNotFound' do
    -        expect do
    -          get :show, params: { id: order.number, token: order.token }
    -        end.to raise_error(ActiveRecord::RecordNotFound)
    +        expect { get :show, params: { id: order.number, token: '' } }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
       end
    
  • storefront/spec/controllers/spree/order_status_controller_spec.rb+8 0 modified
    @@ -64,5 +64,13 @@
             }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
    +
    +    context 'with blank email' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect {
    +          post :create, params: { number: order.number, email: '' }
    +        }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
       end
     end
    
6b32ed7d474a

Merge commit from fork

https://github.com/spree/spreeDamian LegawiecFeb 5, 2026via ghsa
4 files changed · +27 12
  • storefront/app/controllers/spree/orders_controller.rb+9 5 modified
    @@ -10,11 +10,17 @@ class OrdersController < StoreController
     
         before_action :assign_order_with_lock, only: :update
     
    +    rescue_from CanCan::AccessDenied do |exception|
    +      raise ActiveRecord::RecordNotFound
    +    end
    +
         # GET /orders/:id
         def show
           @order = complete_order_finder.new(number: params[:id], token: params[:token], store: current_store).execute.first
     
    -      raise ActiveRecord::RecordNotFound if @order.blank? || !authorize_access
    +      raise ActiveRecord::RecordNotFound if @order.blank?
    +
    +      authorize! :show, @order, params[:token]
     
           @shipments = @order.shipments.includes(:stock_location, :address, selected_shipping_rate: :shipping_method, inventory_units: :line_item)
         end
    @@ -49,9 +55,7 @@ def edit
         private
     
         def authorize_access
    -      return true if @order.user_id.nil?
    -
    -      @order.user == try_spree_current_user
    +      authorize! :show, @order, params[:token]
         end
     
         def find_order_by_cookie
    @@ -65,7 +69,7 @@ def find_order_by_cookie
         end
     
         def accurate_title
    -      if action_name == 'edit' || action_name == 'update'
    +      if ['edit', 'update'].include?(action_name)
             Spree.t(:shopping_cart)
           else
             Spree.t(:order_number, number: @order&.number)
    
  • storefront/app/controllers/spree/order_status_controller.rb+1 1 modified
    @@ -7,7 +7,7 @@ def new; end
         # validate email/order number and redirect to order page
         # POST /order_status
         def create
    -      raise ActiveRecord::RecordNotFound if params[:number].blank?
    +      raise ActiveRecord::RecordNotFound if params[:number].blank? || params[:email].blank?
     
           @order = order_finder.new(number: params[:number], email: params[:email], store: current_store).execute.first
     
    
  • storefront/spec/controllers/spree/orders_controller_spec.rb+9 6 modified
    @@ -105,7 +105,8 @@
       end
     
       describe '#show' do
    -    let(:order) { create(:completed_order_with_totals, store: store, user: user) }
    +    let(:order) { create(:completed_order_with_totals, store: store) }
    +    let(:user) { nil }
     
         it 'renders the show template' do
           get :show, params: { id: order.number, token: order.token }
    @@ -144,13 +145,15 @@
           end
         end
     
    -    context 'when order belongs to another user' do
    -      let(:order) { create(:completed_order_with_totals, store: store, user: create(:user)) }
    +    context 'when token is invalid' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect { get :show, params: { id: order.number, token: 'invalid' } }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
     
    +    context 'when token is missing' do
           it 'raises ActiveRecord::RecordNotFound' do
    -        expect do
    -          get :show, params: { id: order.number, token: order.token }
    -        end.to raise_error(ActiveRecord::RecordNotFound)
    +        expect { get :show, params: { id: order.number, token: '' } }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
       end
    
  • storefront/spec/controllers/spree/order_status_controller_spec.rb+8 0 modified
    @@ -64,5 +64,13 @@
             }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
    +
    +    context 'with blank email' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect {
    +          post :create, params: { number: order.number, email: '' }
    +        }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
       end
     end
    
ea4a5db590ca

Merge commit from fork

https://github.com/spree/spreeDamian LegawiecFeb 5, 2026via ghsa
4 files changed · +27 12
  • storefront/app/controllers/spree/orders_controller.rb+9 5 modified
    @@ -10,11 +10,17 @@ class OrdersController < StoreController
     
         before_action :assign_order_with_lock, only: :update
     
    +    rescue_from CanCan::AccessDenied do |exception|
    +      raise ActiveRecord::RecordNotFound
    +    end
    +
         # GET /orders/:id
         def show
           @order = complete_order_finder.new(number: params[:id], token: params[:token], store: current_store).execute.first
     
    -      raise ActiveRecord::RecordNotFound if @order.blank? || !authorize_access
    +      raise ActiveRecord::RecordNotFound if @order.blank?
    +
    +      authorize! :show, @order, params[:token]
     
           @shipments = @order.shipments.includes(:stock_location, :address, selected_shipping_rate: :shipping_method, inventory_units: :line_item)
         end
    @@ -49,9 +55,7 @@ def edit
         private
     
         def authorize_access
    -      return true if @order.user_id.nil?
    -
    -      @order.user == try_spree_current_user
    +      authorize! :show, @order, params[:token]
         end
     
         def find_order_by_cookie
    @@ -65,7 +69,7 @@ def find_order_by_cookie
         end
     
         def accurate_title
    -      if action_name == 'edit' || action_name == 'update'
    +      if ['edit', 'update'].include?(action_name)
             Spree.t(:shopping_cart)
           else
             Spree.t(:order_number, number: @order&.number)
    
  • storefront/app/controllers/spree/order_status_controller.rb+1 1 modified
    @@ -7,7 +7,7 @@ def new; end
         # validate email/order number and redirect to order page
         # POST /order_status
         def create
    -      raise ActiveRecord::RecordNotFound if params[:number].blank?
    +      raise ActiveRecord::RecordNotFound if params[:number].blank? || params[:email].blank?
     
           @order = order_finder.new(number: params[:number], email: params[:email], store: current_store).execute.first
     
    
  • storefront/spec/controllers/spree/orders_controller_spec.rb+9 6 modified
    @@ -105,7 +105,8 @@
       end
     
       describe '#show' do
    -    let(:order) { create(:completed_order_with_totals, store: store, user: user) }
    +    let(:order) { create(:completed_order_with_totals, store: store) }
    +    let(:user) { nil }
     
         it 'renders the show template' do
           get :show, params: { id: order.number, token: order.token }
    @@ -144,13 +145,15 @@
           end
         end
     
    -    context 'when order belongs to another user' do
    -      let(:order) { create(:completed_order_with_totals, store: store, user: create(:user)) }
    +    context 'when token is invalid' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect { get :show, params: { id: order.number, token: 'invalid' } }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
     
    +    context 'when token is missing' do
           it 'raises ActiveRecord::RecordNotFound' do
    -        expect do
    -          get :show, params: { id: order.number, token: order.token }
    -        end.to raise_error(ActiveRecord::RecordNotFound)
    +        expect { get :show, params: { id: order.number, token: '' } }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
       end
    
  • storefront/spec/controllers/spree/order_status_controller_spec.rb+8 0 modified
    @@ -64,5 +64,13 @@
             }.to raise_error(ActiveRecord::RecordNotFound)
           end
         end
    +
    +    context 'with blank email' do
    +      it 'raises ActiveRecord::RecordNotFound' do
    +        expect {
    +          post :create, params: { number: order.number, email: '' }
    +        }.to raise_error(ActiveRecord::RecordNotFound)
    +      end
    +    end
       end
     end
    

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

11

News mentions

0

No linked articles in our index yet.