You select a product, proceed to checkout, choose a payment method, and complete the transaction through a trusted payment gateway. Everything feels locked down and reliable.

But sometimes, the real security issues are hidden behind a single overlooked request.

This is the story of how I discovered a payment verification vulnerability that allowed a failed transaction to be processed as a successful order.

The Beginning

I was testing the checkout flow of a large e-commerce platform.

To understand how the payment workflow behaved, I added a high-value product to my cart and proceeded with the payment process using UPI.

The website redirected me to a third-party payment gateway where a QR code appeared for payment.

Instead of completing the payment, I clicked the "Back" button on the payment page to cancel the transaction.

Normally, that should have ended the process.

But I wanted to see what happened behind the scenes.

So I opened my proxy tool and started monitoring the network traffic generated after cancelling the payment.

That's when one request immediately stood out from the rest.

The Suspicious Request

Among several API calls, I noticed a payment verification request that looked unusual.

GET /api/v2/paymentverify?token=721c2eb6-9e20-4107-a237-5f21...&status=eyJ1bm1hcHBlZFN0YXR1cyI6InVzZXJDYW5jZWxsZWQiLCJsYXN0TmFtZSI6IiIsInBheW1lbnRNb2RlIjoiIiwidWRmNSI6IndlYiIsImRpc2NvdW50IjoiMC4wMCIsImVkIjoiLi4uIiwic2VydmljZVN0YXR1cyI6InN1Y2Nlc3MiLCJzdGF0dXMiOiJmYWlsdXJlIn0=...
Host: redacted.com
Referer: https://secure.payment-gateway.example/

At first glance, the status parameter looked like some kind of protected token.

But after decoding it, I realized it was simply Base64-encoded JSON data.

And that data contained the entire transaction state.

Decoding the Payload

After decoding the value, I found several payment-related fields:

{
  "serviceStatus": "failure",
  "status": "failure",
  "productAmount": "162990.00",
  "paymentMode": "",
  "bankReferenceNumber": ""
}

The moment I saw this, a question popped into my head:

Why is the payment status coming from the client side?

Because if the backend was actually trusting these values, then theoretically the transaction outcome could be manipulated.

And there was only one way to confirm it.

Testing the Theory

I modified the decoded payload and changed the failed transaction values into successful ones.

{
  "serviceStatus": "success",
  "status": "success",
  "unmappedStatus": "captured",
  "netAmountDebited": "162990.00",
  "bankReferenceNumber": "BANK123456789"
}

Then I encoded the modified JSON again, replaced the original value inside the request, and forwarded it to the server.

Honestly, I expected the server to reject it instantly.

Instead…

The order was marked as successfully paid.

No payment had actually been completed.

No money had been transferred.

Yet the application processed the transaction as legitimate.

At that point, the issue became crystal clear.

The backend was trusting client-controlled payment data.

Understanding the Vulnerability

The core problem was not complicated.

The application relied on user-supplied transaction information instead of independently validating the payment through secure server-side verification.

That meant critical fields such as:

  • payment status
  • service status
  • captured state
  • debited amount
  • bank reference number

could potentially be manipulated before reaching the server.

From a security perspective, this is extremely dangerous because the client should never be trusted to decide whether a payment succeeded.

That decision must come directly from the payment gateway through secure verification mechanisms.

Potential Impact

If exploited maliciously, this type of vulnerability could allow attackers to:

  • place orders without making payment
  • manipulate transaction states
  • bypass payment validation
  • abuse inventory systems
  • create financial loss for the platform

And because the issue existed in the payment verification layer itself, the impact could become significant very quickly.

The Bigger Lesson

One of the most common mistakes in payment integrations is trusting data received from the client side.

Even if a request appears to originate from a legitimate payment flow, every transaction must still be verified server-side using trusted gateway APIs, signatures, hashes, or secure callbacks.

If users can modify payment outcomes directly from their browser or intercepted requests, the payment flow is fundamentally broken.

Final Thoughts

This vulnerability did not require advanced exploitation techniques, sophisticated malware, or complex bypass chains.

It started with something very simple:

A cancelled payment.

And one important question:

"What happens if the client lies?"

Sometimes, that single question is enough to uncover a critical vulnerability.