Versions Affected: All versions of Solidus
Not affected: NONE
Fixed Versions: 4.7.2, 4.6.4
Impact
------
Solidus allows customers to supply `gateway_customer_profile_id` and
`gateway_payment_profile_id` in `payment[source_attributes]` when creating a
payment for their own order. These values are assigned to a new
`Spree::CreditCard` without checking whether the referenced gateway profile
belongs to the requesting user, and card number validation is skipped whenever
a profile id is present.
An authenticated customer, or a guest holding an order token, who already
knows another customer's gateway profile identifiers can attach that stored
credential to a payment on their own order without supplying a card number or
CVV. Depending on the payment gateway integration, completing the order may
then charge the victim's saved card at that store.
The attacker must already possess the victim's gateway-generated identifiers.
Solidus never exposes these to non-admin users, so exploitation requires the
identifiers to have leaked through another channel such as logs, support
tooling, exports, or the gateway dashboard, or for the attacker to be an
admin.
Affected entry points include `POST /api/orders/:order_id/payments`, `PUT
/api/checkouts/:id` at the payment step, `PUT /api/orders/:id`, and any
storefront checkout that uses the permitted checkout payment attributes.
Patches
-------
The fix adds an ownership check in `Spree::PaymentCreate`. A submitted gateway
profile id is rejected with `ActiveRecord::RecordNotFound` (a 404 in the API)
when it is already stored on a credit card that belongs to a different user,
or, for guest orders, on any user's card. Identifiers that are unknown to the
store, such as one-time tokens produced by client-side tokenisation, and
identifiers already owned by the order's user continue to work, so existing
tokenised checkout flows are unaffected.
Fixed in `solidus_core` 4.7.2 and 4.6.4. Older release series will not be
patched and should upgrade.
Workarounds
-----------
Stores that do not rely on client-side tokenisation writing to these
attributes can remove them from the customer-facing permitted attributes in an
initializer:
Spree::PermittedAttributes.source_attributes.delete(:gateway_customer_profile_id)
Spree::PermittedAttributes.source_attributes.delete(:gateway_payment_profile_id)
Do not apply this workaround if your storefront submits a gateway token
through `gateway_payment_profile_id`, for example legacy solidus_stripe 4.x.
Stores in that situation should apply the ownership check from the patch
directly.
Gateway integrations should also charge stored credentials using the customer
profile associated with the order's user rather than identifiers taken from
request parameters.
References
----------
*
https://github.com/solidusio/solidus/security/advisories/GHSA-vgwx-9pm9-8qvjIf you have any questions about how to secure your site please stop by our
Slack:
http://slack.solidus.io/