The modern web is a complex beast. We build intricate user interfaces designed to guide users, validate their inputs, and ensure they follow the rules. But sometimes, in the rush to build a seamless experience, developers forget the golden rule of cybersecurity: Never trust the client.

Recently, while hunting on a major grocery delivery platform (let's call it redacted.com), I stumbled upon a classic example of this oversight. It was a logic flaw that allowed me to completely bypass their business rules regarding minimum order values and item quantity limits, straight through their GraphQL API.

Here's how a simple interception turned rigid business constraints into mere suggestions.

The Setup

I was browsing the storefront of a popular retailer hosted on redacted.com. Like most e-commerce giants, they have rules to ensure profitability and manage inventory.

I noticed two specific constraints while building a test cart:

  1. Quantity Limits: For certain popular items (like avocados, in this case), the UI explicitly stopped me from adding more than 10 units.

2. Minimum Order Value: The checkout button remained stubbornly grayed out until my cart total hit at least $10.00.

These are standard business practices. The UI was doing its job perfectly — preventing me, the average user, from breaking the rules via the browser interface.

But as a bug hunter, my first question is always: Is this rule enforced by the browser, or the server? I decided to find out.

The Hunt

I loaded my cart with 10 avocados. At $0.99 each, my total was $9.90 — just ten cents shy of the checkout minimum. The UI had me locked down.

This is where things got interesting. I fired up my proxy tool to peek under the hood. When I adjusted items in my cart, the application fired off a GraphQL request. I located the specific operation responsible for this: UpdateCartItemsMutation.

It was sending a clean JSON payload to the backend telling it exactly what quantity I wanted. The browser thought the limit was 10. I wondered if the server agreed.

I intercepted the request. Instead of letting the browser send the approved quantity of 10, I modified the payload to demand 15 units.

Technical Breakdown

The vulnerability lay in the fact that the backend GraphQL resolver implicitly trusted whatever integer I sent in the quantity field, without cross-referencing the product's actual constraints database.

Here is a simplified view of the attack.

Target Endpoint: POST https://redacted.com/graphql

The Intercepted Payload:

I took the legitimate request and just nudged the number.

JSON

{
  "operationName": "UpdateCartItemsMutation",
  "variables": {
    "cartItemUpdates": [
      {
        // The ID for the avocado product
        "itemId": "items_xxxx-yyyy",
        // The UI limit was 10. I changed this to 15.
        "quantity": 15,
        "quantityType": "each"
      }
    ],
    "cartType": "grocery",
    "cartId": "123456789"
  }
  // ... rest of the request
}

I sent the modified request on its way. I was expecting a 400 Bad Request or a GraphQL error telling me I'd exceeded the limit.

Instead, the server responded with a 200 OK and a JSON object confirming the cart update with 15 items. I refreshed the browser, and sure enough, my cart was now holding 15 avocados, completely ignoring the UI limit.

Bypassing the Minimum Value

Having proven the server was gullible on quantities, I tested the second rule: the $10 minimum.

I repeated the interception, but this time I set the quantity to just 5 units, dropping my total cart value to $4.95.

JSON

"quantity": 5

Again, the server accepted the update without complaint. When I returned to the UI, the previously grayed-out "Checkout" button was now active, ready to process an order well below the mandatory minimum.

Let's Hunt ! > Satyam > 🔗 Follow me on X