DEV Community

Davi
Davi

Posted on Originally published at blog.mago.team

Business Logic in E-Commerce APIs: Price Manipulation, Negative Quantity, and Coupon Abuse

Business Logic Vulnerabilities in E-Commerce APIs: Price Manipulation, Negative Quantity, and Coupon Abuse

The attacker did not inject SQL or forge a JWT. They sent a valid JSON body with quantity: -1, and the server subtracted the item price from the cart total. The spec never required quantity to be positive.

This is the anatomy of a business logic vulnerability: every parameter is valid, every credential is genuine, every object belongs to the attacker. The scanner returns HTTP 200 with a structurally correct object. The vulnerability lives in the gap between what the API contract allows and what the business requires.

Spec vs. Intent: Why Scanners Cannot See This Attack Class

Business logic vulnerabilities do not escape scanners due to tool limitations. They escape because payloads are syntactically valid and responses are structurally correct.

OWASP WSTG states directly: "This type of vulnerability cannot be detected by a vulnerability scanner and relies upon the skills and creativity of the penetration tester." A scanner testing a cart endpoint receives HTTP 200 with a valid cart object. The field quantity: -1 is an integer within the type the API expects.

The spec says: accept an integer as quantity and apply to the cart. Business intent says: quantity must be greater than zero. The spec never said that. That gap is the vulnerability.

This class is distinct from injection (malformed input), broken auth (invalid credentials), or IDOR (wrong object). Every submitted parameter is valid, every credential is genuine, every object belongs to the attacker. The scanner cannot distinguish this request from a legitimate one because, from the spec's perspective, no difference exists. The fix requires updating the API contract to reflect what the business actually requires. Adding a validation rule to existing code without updating the spec only masks the problem until the next field that lacks a constraint.

Price Field Exposure: When the Client Supplies the Price

When an API accepts price fields in the checkout body instead of fetching the authoritative price from the server-side database, any value the client sends becomes the transaction price.

CVE-2021-36030 affects Magento Commerce versions <=2.4.2 and <=2.3.7. The flaw is improper input validation during checkout, allowing an unauthenticated attacker to alter item prices. CVSS 7.5 (AV:N/AC:L/PR:N/UI:N/I:H). Fixed in versions 2.3.7-p1 and 2.4.2-p2.

CVE-2023-28121 (WooCommerce Payments <=5.6.1) operated at greater scale. The authentication bypass (CVSS 9.8) allowed unauthenticated requests to be sent at the admin-user level, enabling full price and order manipulation. In July 2023, 1.3 million attacks hit 157,000 sites in 48 hours.

CVE-2022-31181 (PrestaShop) documents SQL injection at CVSS 8.1 that, via a crafted sequence of HTTP requests, enables arbitrary data manipulation including order prices and discount records, with escalation to RCE.

The attack pattern: intercept POST /cart or POST /checkout, locate fields named unit_price, price, or amount in the request body, set the value to 0.01. If the checkout total reflects the client-supplied value instead of the catalog price, the endpoint is vulnerable. Burp Suite Param Miner enumerates hidden price fields in checkout flows, including fields absent from the public API documentation.

The root cause is in the specification. The endpoint spec says: process the order at the submitted price. The constraint "verify price matches the product catalog" exists in business intent, not in the spec the server executes. Until the spec includes that constraint, the server behaves correctly by accepting any submitted price.

Negative Quantity and Integer Overflow: Making the Cart Subtract

Accepting quantity: -1 is not a validation oversight. It is the direct result of a spec that defines quantity as integer without specifying the allowed domain, and the business assumption (quantity above zero) was never encoded in the contract.

H1 #364843 (Upserve/OLO) is the canonical example. The researcher submitted 2x ChickenBurger ($12.00) plus (-1)x BreadPudding ($9.00). The cart totaling $18.70 was accepted and processed in production. The server computed the total correctly per the spec. The spec never required quantity > 0.

H1 #388564 (Shipt) used fractional values: quantity: 0.001. The server accepted fractional units, reducing the effective cost below any minimum charge threshold. Bounty: $100. H1 #1562515 (Glovo) was rated Critical at CVSS 9.3: quantity set to 2^63 (9,223,372,036,854,775,808) caused a 64-bit signed integer overflow, converting the line item into a massive negative balance in the attacker's account.

IEEE 754 precision adds systematic abuse independent of overflow. 0.1 + 0.1 + 0.1 evaluates to 0.30000000000000004 in JavaScript and Python. Accumulating rounding errors across 100 cart items at fractional prices produces a total below the true sum. The undercharge grows with cart size. Price calculations must use fixed-point arithmetic (integer cents), not IEEE 754 floats.

The domain probe set for quantity: [0, -1, -100, 0.001, 0.5, 2147483647, 2147483648, 9223372036854775808]. Any non-4xx response to negative or overflow values confirms absent domain validation.

Coupon and Discount Abuse: Stacking, Multi-Redemption, and Race Conditions

Coupon systems fail not because they lack a used flag, but because the check-then-mark sequence is not atomic. The race condition window between validation and state update allows parallel redemptions of the same single-use code.

H1 #157996 (Instacart) demonstrated the mechanism in production. Simultaneous coupon-apply requests all passed the used == false check before any recorded the redemption. The researcher stacked savings by redeeming asynchronously. H1 #1717650 (Stripe) showed the problem persists even after attempted fixes: simultaneous requests continued bypassing the counter, allowing redemptions beyond the specified limit across multiple products.

The referral loop attack requires no concurrency. User A creates a referral code. User B registers with it and receives credit. User B creates a referral code. User A registers a new account with User B's code and also receives credit. Without graph-cycle detection, this loop produces unbounded credit. H1 #277407 (Unikrn) demonstrated self-referral via email manipulation, automatable via PHP script.

Discount stacking operates on the same spec gap. Apply SUMMER20: cart shows $80. Apply NEWUSER10 (10% of current price): total drops to $72. Business intent says the codes are mutually exclusive. The spec says: apply each code if individually valid. Both are valid. The spec never said "one discount per order."

The fix for coupon race conditions requires atomicity: database transaction with SELECT FOR UPDATE or Redis SETNX. Discount eligibility must be evaluated against the original price, not the post-discount price. Referral graphs require cycle detection before any credit is issued.

Detection Methodology: Boundary Testing, Field Enumeration, and Concurrent Probes

Detecting business logic vulnerabilities in e-commerce APIs requires three categories of testing: probing the domain boundaries of numeric fields, enumerating undeclared price parameters, and validating atomicity under concurrency.

For quantity fields, apply the probe set [0, -1, -100, 0.001, 0.5, 2147483647, 2147483648, 9223372036854775808] against every cart endpoint. For price field enumeration, inspect POST bodies across the full checkout flow for fields named price, unit_price, amount, total, item_price, discount, fee. Submit 0.01 to each and compare the checkout total against the catalog price.

For coupon atomicity testing, send N simultaneous apply requests for a single-use code using curl --parallel or Turbo Intruder (N = 10 to 50). If more than 1 request succeeds and the redemption count exceeds 1, the operation lacks guaranteed atomicity. For referral loops, create accounts A and B in the same test session, apply A's code to B, apply B's code to A. If both accounts receive credit, no graph-cycle detection exists in the referral system.

The MAGO team tool (mago.team) automates the boundary probe set and coupon concurrency tests, identifying undeclared price fields and race conditions in a single scan. The canonical methodology reference is OWASP WSTG Section 4.10, covering abuse cases for financial transactions, workflow sequence bypass, and TOCTOU scenarios.

The spec does not restrict quantity to positive integers, so the server accepts -1. The spec does not require price verification against the catalog, so the server uses the client value. The spec does not require atomic coupon redemption, so the race condition exists. The fix is not a validation rule. It is a specification update. Every numeric field in an API contract must carry its full domain: range, sign, precision, and uniqueness constraints. Scanners do not read specs. That is the practitioner's job.

Top comments (0)