Skip to main content
Glama

coupon_abuse_test

Test coupon stacking and alternation to identify discount bypass vulnerabilities in e-commerce systems by applying coupons individually and in alternating sequences.

Instructions

Test coupon stacking and alternation bypass.

Tests each coupon individually, then alternates between coupons to see if discounts compound past the intended limit.

Returns: {"individual_results": [...], "stacking_results": [...], "stacking_possible": bool}.

Side effects: Applies coupons to the cart. May modify cart totals.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
urlYesCoupon application endpoint URL
coupon_endpointYesFull URL for applying coupons, e.g. https://target/cart/coupon
couponsYesCoupon codes to test, e.g. ['NEWCUST5', 'SIGNUP30', 'FREESHIP']
coupon_paramNoForm parameter name for the coupon code
auth_cookieNoSession cookie for authenticated requests
stacking_roundsNoNumber of alternation rounds to test for coupon stacking

Implementation Reference

  • The implementation of the `coupon_abuse_test` tool, which tests coupon stacking and alternation bypass.
    server.tool(
      "coupon_abuse_test",
      "Test coupon stacking and alternation bypass.\n\nTests each coupon individually, then alternates between coupons to see if discounts compound past the intended limit.\n\nReturns: {\"individual_results\": [...], \"stacking_results\": [...], \"stacking_possible\": bool}.\n\nSide effects: Applies coupons to the cart. May modify cart totals.",
      {
        url: z
          .string()
          .describe("Coupon application endpoint URL"),
        coupon_endpoint: z
          .string()
          .describe(
            "Full URL for applying coupons, e.g. https://target/cart/coupon"
          ),
        coupons: z
          .array(z.string())
          .min(1)
          .max(20)
          .describe(
            "Coupon codes to test, e.g. ['NEWCUST5', 'SIGNUP30', 'FREESHIP']"
          ),
        coupon_param: z
          .string()
          .describe("Form parameter name for the coupon code")
          .optional(),
        auth_cookie: z
          .string()
          .optional()
          .describe("Session cookie for authenticated requests"),
        stacking_rounds: z
          .number()
          .min(1)
          .max(20)
          .describe(
            "Number of alternation rounds to test for coupon stacking"
          )
          .optional(),
      },
      async ({
        url,
        coupon_endpoint,
        coupons,
        coupon_param = "coupon",
        auth_cookie,
        stacking_rounds = 5,
      }) => {
        requireTool("curl");
    
        // Phase 1: Test each coupon individually
        const individualResults: Array<{
          coupon: string;
          status: number;
          length: number;
          accepted: boolean;
          response_snippet: string;
        }> = [];
    
        for (const coupon of coupons) {
          const curlArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}",
            "-X",
            "POST",
            "-d",
            `${coupon_param}=${coupon}`,
          ];
          if (auth_cookie) {
            curlArgs.push("-b", auth_cookie);
          }
          curlArgs.push(coupon_endpoint);
    
          const res = await runCmd("curl", curlArgs);
          let body = res.stdout;
          const metaMarker = body.lastIndexOf("__META__");
          let status = 0;
          let length = 0;
          if (metaMarker !== -1) {
            const meta = body.slice(metaMarker + 8).trim();
            const parts = meta.split(":");
            status = parts[0] ? parseInt(parts[0], 10) : 0;
            length = parts[1] ? parseInt(parts[1], 10) : 0;
            body = body.slice(0, metaMarker);
          }
    
          individualResults.push({
            coupon,
            status,
            length,
            accepted: [200, 201, 302].includes(status),
            response_snippet: body.slice(0, 300),
          });
        }
    
        const validCoupons = individualResults
          .filter((r) => r.accepted)
          .map((r) => r.coupon);
    
        // Phase 2: Test coupon alternation/stacking
        const stackingResults: Array<{
          round: number;
          coupon: string;
          status: number;
          accepted: boolean;
          response_snippet: string;
        }> = [];
    
        if (validCoupons.length >= 2) {
          for (let roundNum = 0; roundNum < stacking_rounds; roundNum++) {
            const coupon = validCoupons[roundNum % validCoupons.length];
            const curlArgs = [
              "-sk",
              "-o",
              "-",
              "-w",
              "\n__META__%{http_code}:%{size_download}",
              "-X",
              "POST",
              "-d",
              `${coupon_param}=${coupon}`,
            ];
            if (auth_cookie) {
              curlArgs.push("-b", auth_cookie);
            }
            curlArgs.push(coupon_endpoint);
    
            const res = await runCmd("curl", curlArgs);
            let body = res.stdout;
            const metaMarker = body.lastIndexOf("__META__");
            let status = 0;
            if (metaMarker !== -1) {
              const meta = body.slice(metaMarker + 8).trim();
              const parts = meta.split(":");
              status = parts[0] ? parseInt(parts[0], 10) : 0;
              body = body.slice(0, metaMarker);
            }
    
            stackingResults.push({
              round: roundNum + 1,
              coupon,
              status,
              accepted: [200, 201, 302].includes(status),
              response_snippet: body.slice(0, 300),
            });
          }
        }
    
        // Determine if stacking worked
        const stackingAccepted = stackingResults.filter((r) => r.accepted).length;
        const stackingPossible = stackingAccepted > validCoupons.length;
    
        // Check cart total after stacking
        let cartCheck: string | null = null;
        if (auth_cookie) {
          const cartArgs = [
            "-sk",
            "-o",
            "-",
            "-w",
            "\n__META__%{http_code}:%{size_download}",
            "-b",
            auth_cookie,
            url,
          ];
          const cartRes = await runCmd("curl", cartArgs);
          let cartBody = cartRes.stdout;
          const metaMarker = cartBody.lastIndexOf("__META__");
          if (metaMarker !== -1) {
            cartBody = cartBody.slice(0, metaMarker);
          }
          cartCheck = cartBody.slice(0, 1000);
        }
    
        const result = {
          individual_results: individualResults,
          valid_coupons: validCoupons,
          stacking_results: stackingResults,
          stacking_accepted_count: stackingAccepted,
          stacking_possible: stackingPossible,
          cart_after_stacking: cartCheck,
          hint: stackingPossible
            ? "Coupon stacking/alternation bypass detected! Discounts compounded beyond intended limit."
            : "Coupon stacking blocked. Server enforces single-use correctly.",
        };
    
        return { content: [{ type: "text", text: JSON.stringify(result) }] };
      }
    );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/operantlabs/operant-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server