---
id: "CVE-2026-115450"
kind: "vulnerability"
aliases: ["CVE-2026-115450"]
title: "MarcosCamara01 Ecommerce Template: cart lets users pay less for expensive goods"
severity: "high"
cvss: 7.1
epss: 0.00235
exploited: false
status: "open"
category: "other"
products: [{"name": "MarcosCamara01/ecommerce-template", "fixed": ["e6b364cd668f2ba875cfa7f6d55c63e771715df7"], "affected": ">= commit 2aa8ec53 (2025-11-16), < commit e6b364cd (2026-07-31)", "ecosystem": "github"}]
ecosystems: []
tags: ["authenticated", "ecommerce", "nextjs", "other", "self-hosted", "stripe"]
not_affected_if: ["commit-e6b364cd-or-later", "no-stripe-checkout", "not-this-template"]
published_at: "2026-10-22T16:17:35+00:00"
first_seen_at: "2026-10-23T21:57:31+00:00"
updated_at: "2026-10-25T04:02:48+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-115450", "first_seen_at": "2026-10-23T21:57:31+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-115450", "first_seen_at": "2026-10-24T07:15:51+00:00"}, {"source": "analyst", "url": null, "first_seen_at": "2026-10-25T04:02:48+00:00"}]
---

# MarcosCamara01 Ecommerce Template: cart lets users pay less for expensive goods

The ecommerce template's cart endpoint accepts a product ID and a Stripe price ID as independent fields, so a logged-in user can pay the price of a cheap item while ordering a different product. Every Stripe price ID in the catalogue is public, so the mismatch needs no guessing and can be repeated without limit.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- github:MarcosCamara01/ecommerce-template affected >= commit 2aa8ec53 (2025-11-16), < commit e6b364cd (2026-07-31) fixed e6b364cd668f2ba875cfa7f6d55c63e771715df7

## How to check

Check whether your checkout code descends from MarcosCamara01/ecommerce-template at or after commit 2aa8ec53 (16 Nov 2025) and lacks e6b364cd (run: git merge-base --is-ancestor e6b364cd HEAD). Vulnerable if src/app/api/user/cart/route.ts accepts stripeId in the request body, or if src/app/api/stripe/payment/route.ts builds line_items from item.stripeId. To find past abuse, compare the variant recorded on each order with the amount Stripe actually charged. The charge is valid in Stripe, so it raises no dispute or fraud signal.

## Fix

Pull the upstream repo to a revision that includes commit e6b364cd668f2ba875cfa7f6d55c63e771715df7 (31 Jul 2026). It derives the Stripe price from the variant server-side, and addToCartSchema no longer accepts stripeId. No versioned releases or tags exist, and package.json stays at 0.1.0. Forks must port the change. No configuration workaround exists. Afterwards, audit past orders by comparing each order's variant price with the amount Stripe charged.

## Timeline

- 2026-10-23T21:57:31+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-115450
- 2026-10-24T07:15:51+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-115450
- 2026-10-25T04:02:48+00:00 analyst — Read maintainer fix commit e6b364c (2026-07-31) and Secur0 CNA advisory: no versions/tags exist, affected by commit range from 2aa8ec53 (2025-11-16) to before e6b364cd. No exploitation or PoC found.

## Documents

- [advisory] Secur0 CNA CVE-2026-115450 https://secur0.com/en/cna/cve-list/cve-2026-115450-price-manipulation-stripe-checkout
- [fix] Fix commit e6b364c: derive Stripe price from the variant https://github.com/MarcosCamara01/ecommerce-template/commit/e6b364cd668f2ba875cfa7f6d55c63e771715df7

## From the sources

External Control of Assumed-Immutable Web Parameter (CWE-472) in the cart and checkout flow of MarcosCamara01 Ecommerce Template allows an authenticated user with no special privileges to be charged the price of one product while placing an order for another, because POST /api/user/cart accepts variantId, which determines what the order records, and stripeId, which determines what Stripe charges, as two independent fields of the request body, stores both on the cart row, and no check requires the stripeId to be the one that belongs to the variantId. 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, so the order records a product that was not paid for. Every stripeId in the catalogue is readable by any visitor, so no value has to be guessed. This results in orders for goods at the price of the cheapest item in the catalogue, repeatable without limit, and in order records whose amount does not correspond to the product they list.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
