Skip to content
CVE-2026-115450 ·
High · October 22, 2026

Price manipulation in the Ecommerce Template checkout flow through a client supplied Stripe price identifier

S0
Secur0 CNA
CVE-2026-115450

Description

External Control of Assumed-Immutable Web Parameter (CWE-472) in the cart and checkout flow of MarcosCamara01 Ecommerce Template, in src/app/api/user/cart/route.ts and src/app/api/stripe/payment/route.ts. An authenticated user with no special privileges can be charged the price of one product while placing an order for another.

POST /api/user/cart accepts two independent fields of the request body: variantId, which determines what the order records, and stripeId, which determines what Stripe charges. Both are stored on the cart row and nothing requires the stripeId to be the one that belongs to the variantId. The payload is validated for shape, not for correspondence.

POST /api/stripe/payment builds the Stripe Checkout line items from the stored value, as { price: item.stripeId, quantity }, so the amount charged is the amount of that Stripe price. The checkout.session.completed webhook then creates the order products from the variantId of the same cart row. The charge and the order are therefore functions of two different fields and can be made to disagree.

Every stripeId in the catalogue is readable by any visitor, so no value has to be guessed. Pairing the variantId of the most expensive product with the stripeId of the cheapest yields an order for the former at the price of the latter, repeatable without limit.

The resulting Stripe charge is valid and matches the price identifier it was given, so it raises no payment dispute and no fraud signal. The discrepancy is visible only by comparing the variant recorded on each order against the amount actually charged.

Vulnerability type (CWE)

  • CWE-472: External Control of Assumed-Immutable Web Parameter

Affected versions

Affected from commit 2aa8ec53 of 16 November 2025, which is where the checkout began charging from the stored stripeId while the cart accepted that field from the client, and fixed in commit e6b364cd of 31 July 2026. Default status: unaffected.

The project publishes no versioned releases and the repository carries no git tags, and the version field in package.json has remained at 0.1.0, so an affected revision can only be identified by commit. The flaw is therefore recorded as a commit range rather than a version range.

Score (CVSS 4.0)

High (7.1)

CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N

Privileges required are Low because the attacker needs an ordinary account on the store and nothing more. User interaction is None because the attacker acts alone against the API. Confidentiality on the vulnerable system is None: the attacker learns nothing that was not already published, since the catalogue price identifiers are readable by any visitor, and that public readability is what makes the attack trivial rather than being itself a disclosure. Integrity on the vulnerable system is High because the store records and fulfils an order that was not paid for, and financial loss from an unauthorised movement of money is scored on integrity. Availability is None because the store continues to trade; the loss falls on the operator's margin, not on the operation of the service. The subsequent system metrics are None: Stripe is a separate system but behaves correctly throughout, charging exactly the price identifier it is given.

Solution

Update to a revision that includes commit e6b364cd of 31 July 2026.

There is no configuration that prevents this in an affected revision, because the price identifier is taken from the request body on every add to cart.

Patch

Commit e6b364cd. It adds a buildLineItems() helper that reads the price only from the joined variant.stripeId, so the amount charged and the order recorded both derive from variantId and cannot diverge, and the payment route delegates to it. addToCartSchema no longer accepts stripeId: the server resolves it from the variant through a new findVariantById(), and also validates the requested size against the sizes the variant actually offers. The client callers were updated to stop sending the field, and the new helper is unit tested in isolation.

Credits

  • Darío Rivas - finder
  • Gerard Martinez Guillamon - finder
  • Cristian Fernández Cornejo - analyst
  • Xoán M. Otero Jorge - analyst
  • Secur0 CNA - coordinator
  • MarcosCamara01 - remediation developer

Discovery source: Internal

Official record: CVE-2026-115450

Related records

  • CVE-2026-90896 - unauthenticated checkout session lookup in the same application