payloadcms / payloadcms/payload

[plugin-ecommerce] Cart items with a variant skip stock and price validation in initiatePayment

Open Beginner friendly
#17,866 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

plugin: ecommerce
Dominant language
TypeScript
Stars
44.8k
Forks
4.2k
Avg merge
2d 21h
Merged PRs (30d)
53

Description

Describe the Bug

In initiatePayment, the validation block for variants can never run. The outer condition excludes items that have a variant, but the variant check is nested inside it:

if (item.product && !item.variant) {
  // product is fetched and validated here
  if (item.variant) {
    // variant is fetched and validated here — unreachable,
    // the outer branch requires !item.variant
  }
}

(initiatePayment.ts lines 201 and 253 at v3.88.0)

As a result, any cart item that carries a variant reaches the payment adapter with no stock check and no price-field check. With inventory tracking enabled, a variant with inventory 2 can be bought in any quantity. In our reproduction the request then failed inside the payment adapter with HTTP 500, so the customer sees a server error instead of the out-of-stock message, and with a live key the payment would proceed.

A related observation in the same area: confirmOrder destructures productsValidation from its arguments but never calls it.

The amount itself comes from the server-side cart subtotal, so we did not find a way for a client to influence the charged price through this path — it appears to be a correctness and availability defect, not a price-manipulation one.

Link to the code that reproduces this issue

https://github.com/payloadcms/payload/blob/v3.88.0/packages/plugin-ecommerce/src/endpoints/initiatePayment.ts#L201-L253 — reproduced on the official ecommerce template with no modifications.

Reproduction Steps
  1. Start the official ecommerce template with @payloadcms/plugin-ecommerce 3.88.0, inventory tracking on, Stripe test keys.
  2. Create a product with variants; give one variant inventory 2.
  3. As a customer, add 5 of that variant to the cart and call initiatePayment.
  4. Expected: HTTP 400 with OutOfStock. Actual: validation is skipped and the request reaches the payment adapter; with a Stripe test key it returns HTTP 500.
  5. Control case: the same flow on a product without a variant and inventory 2 correctly returns HTTP 400.
Which area(s) are affected?

plugin: ecommerce

Environment Info
Payload 3.88.0
@payloadcms/plugin-ecommerce 3.88.0
Node 22
PostgreSQL 17.10 (also observed on MongoDB)
Official ecommerce template

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/plugin-ecommerce/src/endpoints/initiatePayment.ts around lines 201-253 and reproduce the variant-cart flow described against the official ecommerce template. Confirm that an over-quantity variant returns HTTP 400 with OutOfStock, while the control product path continues to validate correctly; also inspect the nearby confirmOrder productsValidation observation.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, payments
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.