bugproof-demo-shoplite · case_20260925_318b
Negative quantity accepted in setQuantity — negative cart total enables fraudulent charge
The bug allowed shoppers to enter negative quantities for cart items, such as "-3", which the system interpreted as a valid quantity. This happened because a recent code change replaced the previous check that rejected negative numbers with a new one that only verified whether the quantity was a finite number, failing to detect negative values. The fix adds an additional check to reject any quantity less than zero, ensuring only valid positive quantities are accepted.
Written by IBM watsonx.ai ibm/granite-4-h-small from the case evidence.
Reproduced — a new test failed before the fix
3 of 3 repro tests failed on the unfixed code
AssertionError: expected function to throw an error, but it didn't
Culprit commit identified
Named from git history · matches the seeded answer key
c3fb68f refactor(cart): accept numeric strings for quantities
Fixed — the repro test and the full suite pass
110 of 110 tests pass after the fix
Reviewed — the Critic approved
Fix is exactly one character change (+`|| value < 0`) to the guard condition in parseQuantity — minimal and targeted
APPROVED
Tests untouched — the fix changed no existing test
The fix commit only adds the repro test; no existing test was modified or deleted (git diff of the fix commit)
+ tests/bugproof/case_20260925_318b.test.ts
Written by the Fixer, whose edit permission covers src/ only; the check above confirms no existing test changed.
diff --git a/src/cart/cart.ts b/src/cart/cart.ts
index 467f700..3ccdb23 100644
--- a/src/cart/cart.ts
+++ b/src/cart/cart.ts
@@ -69,6 +69,6 @@ export function itemCount(cart: Cart): number {
/** Quantities arrive as numbers from code and as strings from form fields and JSON payloads. */
export function parseQuantity(input: number | string): number {
const value = typeof input === "string" ? Number(input.trim()) : input;
- if (!Number.isFinite(value)) throw new InvalidQuantityError(input);
+ if (!Number.isFinite(value) || value < 0) throw new InvalidQuantityError(input);
return Math.trunc(value);
}The repro test fails on the code before the fix and passes on the fix.
git clone https://github.com/GegarinSagolsem/bugproof-demo-shoplite && cd bugproof-demo-shoplite && npm ci git checkout e21313f~1 # the code before the fix git checkout e21313f -- tests/bugproof/case_20260925_318b.test.ts # add the repro test npx vitest run tests/bugproof/case_20260925_318b.test.ts # fails: the bug is reproduced git checkout e21313f # the fix npx vitest run tests/bugproof/case_20260925_318b.test.ts # passes
- function toQuantity(quantity: number): number {
- if (!Number.isInteger(quantity) || quantity < 1) throw new InvalidQuantityError(quantity);
- return quantity;
- }
+ export function parseQuantity(input: number | string): number {
+ const value = typeof input === 'string' ? Number(input.trim()) : input;
+ if (!Number.isFinite(value)) throw new InvalidQuantityError(input);
+ return Math.trunc(value);
+ }Negative quantities (e.g. quantity="-3") were silently accepted by parseQuantity in src/cart/cart.ts because the refactor commit c3fb68f replaced toQuantity() (which guarded quantity < 1) with parseQuantity() (which only checked isFinite). This allowed a PATCH request to set cart item quantity to -3, producing a cart total of -4549.46 INR, which the payment gateway accepted as a fraudulent negative charge. Fix: added `|| value < 0` to the parseQuantity guard condition. All 110 tests pass including 3 new repro tests covering numeric -3, string '-3', and direct parseQuantity calls.