CVE-2026-94462

CVE-2026-94462 is a high-severity security vulnerability in spree_api (rubygems), affecting versions >= 5.4.0, < 5.4.4. It is fixed in 5.4.4, 5.5.4.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

Spree: Broken Access Control in PATCH /api/v3/store/carts/:id/associate (IDOR)

The Store API v3 endpoint PATCH /api/v3/store/carts/:id/associate binds a guest cart to the authenticated caller without verifying possession of that cart. It locates the cart by prefixed ID only, current_store.carts.where(user: [nil, current_user]).find_by_prefix_id!(params[:id]), and omits the authorize!(:update, @cart, cart_token) check that every other action in the controller performs via CartResolvable. Because prefixed IDs are a reversible Sqids encoding of the auto-increment primary key (obfuscation, not a token), an authenticated customer can name arbitrary guest cart IDs, take them over, and read the checkout addresses stored on them. This is broken access control / IDOR, reachable by any low-privilege registered user.

Severity

Requires an authenticated store account and depends on target guest carts already carrying an address and not yet being associated, on a store not running in login_required mode. Confidentiality impact is the driver (guest checkout PII); integrity impact is limited and recoverable (cart reassignment + email overwrite on an in-progress cart). Not Critical: the action is gated behind authentication (PR:L, not PR:N) and constrained by cart state, so it is not anonymously exploitable.

Details

Root cause: associate skips the cart-possession check its sibling actions enforce and trusts a guessable identifier as the sole locator.

Entry point. Spree::Api::V3::Store::CartsController#associate (carts_controller.rb:88-96), guarded only by prepend_before_action :require_authentication!, only: [:index, :associate]. That requires the caller be authenticated; it does not tie the request to a specific guest cart.

# spree/api/app/controllers/spree/api/v3/store/carts_controller.rb:88-96
# PATCH /api/v3/store/carts/:id/associate
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

Missing check. find_cart_for_association (carts_controller.rb:177-178) resolves any guest cart (user IS NULL) in the store by ID with no authorize!(..., cart_token). Contrast CartResolvable#find_cart!, which binds the token.

# spree/api/app/controllers/spree/api/v3/store/carts_controller.rb:177-178
def find_cart_for_association
  current_store.carts.where(user: [nil, current_user]).find_by_prefix_id!(params[:id])
end

Identifier. prefixed_id is "cart_" + SQIDS.encode([id]) with SQIDS = Sqids.new(min_length: 10) (prefixed_id.rb:17,56), default alphabet, no salt, no blocklist. Sqids is non-cryptographic and reversible, so candidate IDs are derivable offline from sequential primary keys.

# spree/core/app/models/concerns/spree/prefixed_id.rb:17-56
SQIDS = Sqids.new(min_length: 10)

def prefixed_id
  return nil unless id.present?

  "#{self.class._prefix_id_prefix}_#{Spree::PrefixedId::SQIDS.encode([id])}"
end

Data flow. Spree.cart_associate_service.call(guest_order: @cart, user: current_user, guest_only: true) reassigns the owner and overwrites email, preserving existing addresses via bill_address ||= / ship_address ||=. render_cart then serializes billing_address/shipping_address (first_name, last_name, address1, address2, city, postal_code, phone, company) back to the caller.

PoC

Preconditions: attacker holds an ordinary store account (self-service registration) and the store's publishable key (a front-end credential, present in any headless storefront bundle); one or more guest carts carry checkout addresses; store is not in login_required mode.

  1. Authenticate: POST /api/v3/store/auth/login → attacker JWT.
  2. Derive candidate IDs offline: "cart_" + Sqids.encode([n]) for a range of n.
  3. For each candidate: PATCH /api/v3/store/carts/<id>/associate with the attacker JWT. A hit returns 200 with the victim's billing_address/shipping_address; non-guest or missing carts return 404/422.

Impact

Confidentiality: an authenticated attacker can enumerate guest cart IDs and read checkout PII (name, street, postal code, phone) on carts they don't own. Integrity: limited and recoverable, each call reassigns the guest cart and overwrites its email, disrupting the original guest's in-progress cart. Requires a registered account, so not anonymously exploitable.

CVE-2026-94462 has a CVSS score of 7.1 (High). The vector is network-reachable, low privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (5.4.4, 5.5.4); upgrading removes the vulnerable code path.

Affected versions

spree_api (>= 5.4.0, < 5.4.4) spree_api (>= 5.5.0, < 5.5.4)

Security releases

spree_api → 5.4.4 (rubygems) spree_api → 5.5.4 (rubygems)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

Update to Spree 5.4.4 or 5.5.4. Your storefront, based on https://github.com/spree/storefront, doesn't need any updates because it has always sent a cart token when associating carts; this is a backend issue.

Frequently Asked Questions

  1. What is CVE-2026-94462? CVE-2026-94462 is a high-severity security vulnerability in spree_api (rubygems), affecting versions >= 5.4.0, < 5.4.4. It is fixed in 5.4.4, 5.5.4.
  2. How severe is CVE-2026-94462? CVE-2026-94462 has a CVSS score of 7.1 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of spree_api are affected by CVE-2026-94462? spree_api (rubygems) versions >= 5.4.0, < 5.4.4 is affected.
  4. Is there a fix for CVE-2026-94462? Yes. CVE-2026-94462 is fixed in 5.4.4, 5.5.4. Upgrade to this version or later.
  5. Is CVE-2026-94462 exploitable, and should I be worried? Whether CVE-2026-94462 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether CVE-2026-94462 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix CVE-2026-94462?
    • Upgrade spree_api to 5.4.4 or later
    • Upgrade spree_api to 5.5.4 or later

Other vulnerabilities in spree_api

Stop the waste.
Protect your environment with Kodem.