[GHSA-6p7r-vx57-9gw3] Missing authorization check on return item inventory units allows cancelling other customers' returns

4 views
Skip to first unread message

Jared Norman

unread,
Oct 7, 2026, 11:38:18 AM (5 days ago) Oct 7
to solidus-security
Versions Affected: All versions of Solidus
Not affected: NONE
Fixed Versions: 4.7.2, 4.6.4

Impact
------

An authenticated customer can cancel another customer's in-progress return.
`POST /api/orders/:order_id/return_authorizations` accepts
`return_items_attributes[][inventory_unit_id]` values from any order, and
creating a return item for an inventory unit cancels every other active return
item for that unit.

Nothing ties the inventory units in the request to the order in the URL:

* `Spree::Api::ReturnAuthorizationsController#create` authorizes against the
  `ReturnAuthorization` class, so the ownership block in
  `Spree::PermissionSets::DefaultCustomer` is never evaluated. `load_order`
  only checks access to the parent order.
* `inventory_unit_id` is a permitted nested attribute for every caller.
* `Spree::ReturnItem#belongs_to_same_customer_order` returns early when there
  is no customer return, which is always the case when a return authorization
  is created.

The return authorization saves with a return item for another order's unit,
and the `after_create :cancel_others` callback on `Spree::ReturnItem` cancels
the other order's return items for that unit.

Any customer with a shipped order can cancel other customers' pending return
items. The victim's return has to be re-authorized, and a stray return item is
left on the victim's inventory unit.

No data is disclosed and the attacker gains nothing financially:
reimbursements take their order from the inventory unit, so any refund goes to
the victim's order.

Patches
-------

Fixed in `solidus_core` 4.7.2 and 4.6.4. Older release series will not be
patched and should upgrade.

`Spree::ReturnItem` now validates that its inventory unit belongs to the
return authorization's order. Code or specs that attach a return item to a
return authorization on a different order will get a validation error.

Workarounds
-----------

If you cannot upgrade, add the same validation in an initializer:

    # config/initializers/solidus_return_item_order_validation.rb
    Rails.application.config.to_prepare do
      Spree::ReturnItem.validate do
        next unless inventory_unit_id_changed? || return_authorization_id_changed?
        next unless return_authorization && inventory_unit

        if return_authorization.order_id != inventory_unit.order_id
          errors.add(:base, I18n.t("spree.return_items_cannot_be_associated_with_multiple_orders"))
        end
      end
    end

Neither the patch nor the workaround repairs existing data. To find return
items on a different order than their return authorization:

    Spree::ReturnItem
      .joins(:return_authorization, inventory_unit: :shipment)
      .where("spree_return_authorizations.order_id != spree_shipments.order_id")

References
----------

* https://github.com/solidusio/solidus/security/advisories/GHSA-6p7r-vx57-9gw3

If you have any questions about how to secure your site please stop by our
Slack: http://slack.solidus.io/

Reply all
Reply to author
Forward
0 new messages