How Systematic Testing of Payment Systems Uncovered Multiple Critical Vulnerabilities
In penetration testing, the difference between finding surface-level issues and uncovering critical business logic flaws often comes down to one thing: continuity. While automated scanners can identify common vulnerabilities, it's the persistent, methodical exploration of an application's core functionality that reveals the most impactful security gaps.
This article shares real findings from a penetration test on an insurance platform, demonstrating how continuous, focused testing of payment flows led to the discovery of five critical vulnerabilities. Each finding built upon lessons learned from the previous one, showcasing why giving up after the first bug means leaving the most valuable discoveries on the table.
The Target: Insurance Platform Architecture
The application was a comprehensive insurance platform offering multiple product lines:
Products:
- Travel Insurance (Individual & Corporate)
- Health Insurance (Corporate only)
- Motor/Car Insurance (Individual & Corporate)
Payment Methods:
- Credit/Debit Card
- Loyalty Points
- Cashback
This complexity created numerous payment flows, each potentially harboring unique vulnerabilities. The key was not just testing each flow once, but understanding how they interconnected and where business logic could be manipulated.
Finding #1: Business Logic Bypass in Car Insurance Age Restrictions
The Business Rule
The insurance company had a clear underwriting policy for motor insurance based on vehicle age:
- Cars ≤10 years old: Eligible for Comprehensive insurance
- Cars >10 years old: Must purchase Third Party insurance only
This makes business sense — older vehicles carry higher risk and shouldn't be covered comprehensively at standard rates.
Initial Discovery
While testing the motor insurance quotation flow, I noticed the age restriction was enforced client-side. When selecting a 2010 vehicle and attempting to choose Comprehensive insurance, I could manipulate the request to bypass the frontend validation.
First attempt: Added a single old car (2010) with Comprehensive insurance via request manipulation.
Result: The cart amount became 0. The payment process blocked transactions with zero or negative amounts.
At this point, many testers might conclude the validation works — after all, you can't complete the purchase. But this is where continuity matters.
The Breakthrough
Instead of moving on, I asked: Why does the amount become zero? Is the system detecting the manipulation, or is there a pricing logic flaw?
I noticed the system allowed up to 5 cars on a single policy. This opened a new attack vector.
Second attempt: Added two cars to the cart:
- Car 1: New vehicle (2015) with Third Party insurance — legitimate, properly priced
- Car 2: Old vehicle (2010) with Comprehensive insurance — exploited via request manipulation, price = 0
Result: The system calculated the total based only on the legitimate car but issued policies for BOTH vehicles.
Steps to Reproduce:
- Create quotation for motor insurance
- Add first car: year 2015, Third Party insurance (legitimate)
- Add second car: year 2010
- Intercept request and modify insurance type to Comprehensive for the 2010 vehicle
- Proceed to payment
- Complete payment (charged only for the first car's Third Party insurance)
- Receive two separate policies:
- Policy 1: 2015 vehicle with Third Party ✓
- Policy 2: 2010 vehicle with Comprehensive (should be prohibited)
Business Impact: The company now has a comprehensive policy on a high-risk old vehicle, paid for at third-party rates — violating their underwriting standards and exposing them to significant financial risk.
The Lesson in Continuity
If I had stopped after seeing the zero-amount cart, I would have missed this vulnerability entirely. The key was understanding that:
- Client-side validation is never sufficient
- Pricing logic can be separate from policy issuance logic
- Batch operations (multiple items in cart) often have different validation than single items
Finding #2: Quotation Manipulation During Active Payment Session
The Discovery Path
After finding the car insurance logic flaw, I shifted focus to other product lines. The success with manipulating quotations in motor insurance made me wonder: What happens if you modify a quotation AFTER starting the payment process?
This is where continuity thinking comes in — taking lessons from one finding and applying them to different contexts.
The Vulnerability
In both Travel and Health insurance products, the quotation modification API remained accessible even after proceeding to the payment page. The application failed to validate that the final policy matched what the customer actually paid for.
Affected Products:
- Travel Insurance ✓
- Health Insurance ✓
Steps to Reproduce:
Create Initial Quotation:
- Product: Travel Insurance
- Insurance Class: Basic
- Number of Members: 2
- Total Amount: $200
Proceed to Payment Page:
- Payment page loads with amount locked at $200
- Payment gateway initialized
Modify Quotation via API (while on payment page):
- Replay the quotation modification API's
- Change insurance class: Basic → Premium
- Add additional members: 2 → 5
- New quotation value would be $800+ if recalculated
Complete Payment:
- Pay the original $200 amount
- Payment processes successfully
Download Policy:
- Policy reflects the MODIFIED quotation
- Insurance class: Premium ✓
- Number of members: 5 ✓
- Amount paid: $200 (should be $800+)
Why This Worked
The application had a critical flaw in its state management:
- The payment amount was calculated and locked when entering the payment page
- The quotation modification API had no session state validation
- Policy generation pulled data from the quotation record, not from the payment transaction
- No integrity check verified quotation hadn't changed between payment initiation and completion
The Continuity Mindset
This vulnerability emerged from:
- Pattern Recognition: Seeing quotation manipulation work in one context (motor insurance)
- State Exploration: Testing what happens at different stages of the payment flow
- API Investigation: Not limiting testing to UI flows — exploring backend APIs directly
Most importantly, it required not accepting the "happy path" as the only path.
Finding #3: Loyalty Points Refund Abuse After Policy Issuance
Expanding the Attack Surface
At this point, I had found two logic flaws in the quotation and payment process. But I hadn't fully explored all payment methods. The platform offered three payment options: card, loyalty points, and cashback.
The continuity principle here: Don't just test different products — test different payment methods across those products.
The Vulnerability
The loyalty points payment system had a critical flaw: the cancellation API endpoint lacked proper state validation and could be called even after the policy was fully issued and active.
Affected Products:
- Travel Insurance ✓
- Health Insurance ✓
- Motor Insurance ✗ (not vulnerable)
The Discovery Process
While testing the loyalty points payment flow, I noticed the API structure:
Note: The API endpoints shown below are examples for demonstration purposes only and do not represent actual production APIs.
POST /api/payment/loyalty/initiate- Start loyalty points paymentPOST /api/payment/loyalty/cancel- Cancel loyalty points paymentPOST /api/payment/card/process- Process card payment
During normal testing, the cancel endpoint worked as expected — you could cancel before completing payment. But then I asked: What if I call this AFTER the payment is complete?
Steps to Reproduce:
Create Quotation:
- Product: Travel Insurance
- Total Amount: $500
Initiate Partial Payment with Loyalty Points:
- Pay $300 using loyalty points
- Remaining amount: $200
Complete Payment with Card:
- Pay remaining $200 with credit card
- Payment successful
Policy Issued:
- Download active policy
- Policy status: Active ✓
- Coverage: Valid ✓
Call Loyalty Points Cancellation API:
POST /api/payment/loyalty/cancel- Include original transaction ID
- API returns success
Result:
- Loyalty points refunded: +$300 points back to account ✓
- Policy status: Still Active ✓
- Total paid: $200 (should be $500)
Why No UI Option Existed
Importantly, there was no button or UI element to cancel loyalty points after payment completion. This endpoint was only meant to be accessible during the payment process, before finalization.
The vulnerability was discovered through:
- API Enumeration: Cataloging all payment-related endpoints
- State Testing: Replaying requests at different stages of the payment lifecycle
- Authorization Testing: Checking if endpoints validated the current transaction state
The Continuity Pattern Emerging
By this point, three critical vulnerabilities had been discovered, and a clear pattern emerged:
Finding #1: Business logic can be bypassed when validation is split between frontend and backend Finding #2: State transitions in payment flows are often poorly validated Finding #3: Payment method APIs may lack proper lifecycle controls
This is the essence of continuity in penetration testing: Each vulnerability is not just a finding — it's a lesson that guides your next test.