Browse CTFs New CTF Sign in

Quantity manipulation

web_injection_logic Difficulty 1–5 30 min certifiable

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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 (parseInt in 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] where MAX_ALLOWED_QUANTITY is a business-defined ceiling (e.g., 999). Use arbitrary-precision arithmetic (DECIMAL(19,4) in SQL, Python's decimal.Decimal) for all monetary calculations to prevent floating-point rounding errors and integer overflow. Never store monetary totals in signed integer columns — use DECIMAL or NUMERIC types.

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 attackparseInt('-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.