Quantity manipulation
Theory
Why This Matters
A 2018 bug bounty report against a digital goods marketplace described an attacker adding -1 units of a paid software license to their cart. The total price displayed as -$29.99, and the checkout processed successfully, crediting the attacker's account with $29.99 in store credit rather than charging them. The platform's server-side price calculation used a simple multiplication: total = quantity * unit_price. With quantity=-1, the arithmetic produced a negative total, which the payment processing module interpreted as a credit issuance. A separate class of finding — integer overflow in total price computation — was demonstrated against a legacy retail system: adding 2,147,483,648 units of a $1 item caused a signed 32-bit integer overflow (INT_MAX + 1 = -2,147,483,648), producing a negative total that again triggered a credit rather than a charge.
Core Concept
Quantity manipulation attacks exploit the application's failure to enforce that cart quantities are positive integers within a sane range. The attack surface has four distinct variants.
Negative quantity: the server performs total = quantity * price without asserting quantity > 0. A negative quantity produces a negative total, which may trigger a refund, credit issuance, or a checkout that charges $0.
Integer overflow: if the total price is stored in a signed integer type (INT32, INT64), multiplying a large quantity by a unit price can exceed the type's maximum value, wrapping to a large negative number. This is more likely in compiled backend components or database stored procedures using fixed-width integer columns.
Zero-quantity order: a zero-quantity cart item passes a positivity check (quantity >= 0) but creates an order line for $0. This can probe fulfillment systems — does the platform ship zero items, or does it reveal internal inventory or fulfillment details in the order confirmation?
Fractional quantities: if the API accepts floating-point quantities (quantity=0.0001), a very small fraction of a high-price item may produce a total that rounds to $0.00 before the charge is applied, particularly if the platform truncates rather than rounds monetary values.
The correct fix combines: server-side type enforcement (parseInt(quantity, 10) followed by a range check), positive-only clamping (reject any quantity < 1), and independent price calculation (compute the total server-side from the catalog price, never from a client-supplied price field or a derived total).
Technical Deep-Dive
# Attack 1: Negative quantity — add -1 units to cart
POST /api/cart/items HTTP/1.1
Host: shop.example.com
Cookie: session=abc123
Content-Type: application/json
{"product_id": "SOFTWARE-PRO", "quantity": -1}
# Server responds (vulnerable):
# {"cart_total": -29.99, "line_items": [{"product": "SOFTWARE-PRO", "qty": -1, "total": -29.99}]}
# Attack 2: Checkout with negative total
POST /api/checkout HTTP/1.1
Host: shop.example.com
Cookie: session=abc123
Content-Type: application/json
{"cart_id": "CART-888", "payment_method": "card_tok_visa_4242"}
# Vulnerable response: {"charged": -29.99, "credit_issued": 29.99}
# Attack 3: Integer overflow (signed 32-bit total in cents)
# unit_price = $1.00 = 100 cents; INT32_MAX = 2147483647
# quantity needed to overflow: 2147483647 / 100 = 21,474,836 units
POST /api/cart/items HTTP/1.1
Host: shop.example.com
Cookie: session=abc123
Content-Type: application/json
{"product_id": "CHEAP-ITEM", "quantity": 2147483648}
# If total stored in INT32: 2147483648 * 100 = 214748364800 > INT32_MAX
# Wrapped value: 214748364800 mod 2^32 = 214748364800 - 4294967296*50 = negative
# Attack 4: Fractional quantity
POST /api/cart/items HTTP/1.1
Host: shop.example.com
Cookie: session=abc123
Content-Type: application/json
{"product_id": "PREMIUM-COURSE", "quantity": 0.0001}
# total = 0.0001 * 299.99 = 0.029999 -> rounds/truncates to $0.00
# Systematic quantity fuzzing
import requests
s = requests.Session()
s.cookies.set('session', 'abc123')
BASE = 'https://shop.example.com'
test_quantities = [
-1, -100, -2147483648, # negative
0, # zero
0.0001, 0.5, 0.9999, # fractional
2147483647, 2147483648, # INT32 boundary
9223372036854775807, # INT64 max
1e308, # float max
'1; DROP TABLE cart_items--', # injection probe
]
for qty in test_quantities:
r = s.post(f'{BASE}/api/cart/items',
json={'product_id': 'TARGET-ITEM', 'quantity': qty})
total = r.json().get('cart_total', 'N/A')
print(f'qty={qty!r:30} -> status={r.status_code} total={total}')
Security Assessment Methodology
- Identify all quantity input fields — Map every endpoint that accepts a quantity: add-to-cart, update-cart, bulk purchase, subscription seat count, and API rate plan quantity selectors.
- Test negative quantities — Submit quantity=-1 for each identified endpoint. Check whether the cart total becomes negative and whether checkout processes with a negative total or credit issuance.
- Test zero quantity — Submit quantity=0. Observe whether a $0 line item is created and whether it can be checked out, potentially triggering fulfillment without payment.
- Test fractional quantities — Submit quantity=0.0001 (or other small decimals). Check whether the total rounds or truncates to $0.00 at any point in the checkout flow.
- Test integer overflow boundaries — Submit quantities near INT32_MAX (2,147,483,647) and INT64_MAX. Use Burp Intruder with a list of boundary values. Observe whether the total wraps to a negative value.
- Verify server-side price calculation — Confirm that modifying the price or total fields in the request has no effect on what is charged. If the total is computed server-side from quantity * catalog_price, confirm that catalog_price cannot be overridden by a client-supplied value.
Defensive Countermeasure — Enforce quantity validity at the API boundary: parse the input as a strict integer (
parseIntin JavaScript,int()in Python, explicit type binding in ORM), reject non-integer values with 400 Bad Request, and clamp the result to the range[1, MAX_ALLOWED_QUANTITY]whereMAX_ALLOWED_QUANTITYis a business-defined ceiling (e.g., 999). Use arbitrary-precision arithmetic (DECIMAL(19,4)in SQL, Python'sdecimal.Decimal) for all monetary calculations to prevent floating-point rounding errors and integer overflow. Never store monetary totals in signed integer columns — useDECIMALorNUMERICtypes.
Common Assessment Errors
- Only testing negative values — Integer overflow at INT32_MAX and fractional quantities are distinct attack vectors with different root causes. Test all four variants independently.
- Missing the checkout step — A negative cart total that the server displays correctly may still be rejected at checkout. Confirm the full flow: add item, view cart total, attempt checkout, observe charge amount.
- Assuming JavaScript parseInt prevents the attack —
parseInt('-1')in JavaScript returns -1 cleanly. The validation must include a range check (if (qty < 1) reject) after parsing — parsing alone is insufficient. - Not testing quantity in non-cart contexts — Subscription seat counts, API rate plan quantities, and bulk license purchases often go through different code paths than the shopping cart. Test all quantity inputs independently.
- Overlooking the fulfillment side effect of zero quantity — A zero-quantity order may not produce a charge but may still trigger inventory deduction, shipping label generation, or license issuance in poorly coupled backend systems.
- Ignoring the interaction with coupon logic — A negative quantity combined with a percentage discount may produce a doubly negative total (negative * negative = positive charge to the platform). Test quantity manipulation in conjunction with coupon application.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0007 | Knowledge of authentication, authorization, and access control methods | Connects input validation enforcement to authorization of checkout and fulfillment operations |
| K0065 | Knowledge of web application security testing techniques | Develops boundary value testing and integer overflow exploitation in web cart APIs |
| K0070 | Knowledge of system and application security threats and vulnerabilities | Classifies negative quantity and integer overflow as distinct business logic threat variants |
| S0001 | Skill in conducting vulnerability scans and recognizing vulnerabilities in security systems | Trains systematic quantity boundary fuzzing across all cart and purchase endpoints |
| T0028 | Identify and analyze vulnerabilities and risks in web applications | Applies type-enforcement and arithmetic invariant analysis to identify quantity manipulation risks |
| T0570 | Perform technical security assessments of web applications | Structures quantity manipulation assessment from input field enumeration through credit issuance proof |
Further Reading
- OWASP Testing Guide v4.2, OTG-BUSLOGIC-005: Test Number of Times a Function Can Be Used Limits — OWASP Foundation
- CWE-190: Integer Overflow or Wraparound — MITRE CWE Database
- Stuttard, D. & Pinto, M. (2011). The Web Application Hacker's Handbook, 2nd Ed., Chapter 11 — Wiley
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.