y4ss3r
cyber-sec engineer
← cd ../writeups
Bug Bounty/Payments · Logic/Intermediate/Oct 2026/6 min

My first bug bounty: a split-payment logic flaw in an airline app

TL;DR — How a wallet + card split payment left a booking confirmed while the card was never charged — my first valid bug bounty finding, in a major airline's app.

MobileBug BountyLogic FlawPayments
[ machine card / cover ]

My first valid bug bounty finding — a payment/booking state mismatch in a major airline's booking flow. The program and all identifying details (PNR, route, flight number, dates) are redacted for confidentiality.

TL;DR

Booking a flight with a split payment — part from the airline wallet balance, the rest on a MADA/Visa card — left the booking Confirmed with a PNR and an invoice email issued, while the card was never actually charged. The app then fell into an inconsistent state: trying to cancel showed a "Continue purchase" prompt, as if the payment were still unfinished, even though the booking was already confirmed.

It was the first bug of my career, and it was rewarded in roughly the ~$1,000 range.

Not a payload — a state machine

This isn't an injection or a broken endpoint. It's a business-logic / state-machine flaw: two systems that should share a single source of truth — payment capture and booking status — disagreed about what actually happened. The booking side believed it was paid; the card side never captured the money.

Proof of concept (redacted)

  1. Select a flight and proceed to checkout.
  2. At payment, split the amount: apply part from the wallet balance, pay the remainder with a card.
  3. Complete the card step (3DS/OTP) until the app shows Payment Success.
  4. Observe: booking is Confirmed, a PNR is issued, an invoice email is generated.
  5. Check the card statement: no charge is posted — the balance is unchanged.
  6. Attempt to cancel the confirmed booking → the app shows "Continue purchase" instead of a normal cancellation / refund flow.

Expected vs actual

Expected: after a successful payment the booking is confirmed and the payment reaches a consistent final state (Authorized → Captured/Posted). Cancellation works normally, or shows clear refund rules.

Actual: booking becomes Confirmed and a PNR/invoice is issued, but the card amount is unchanged, and cancellation behaves as if the payment were incomplete.

Why it matters

  • Duplicate bookings / double charges — a customer who sees no card charge may retry and book twice.
  • Reconciliation risk — split-tender transactions recorded inconsistently (wallet deducted, card not captured, or a delayed capture never reflected).
  • Refund / cancellation disputes — a user stuck on "Continue purchase" can miss a cancellation window and eat avoidable fees.
  • Unify the payment state machine for split tender (wallet + card) so booking and cancellation read the same source of truth.
  • Model explicit states: Pending Authorization → Authorized → Captured → Failed, plus Wallet Deducted / Reversed.
  • If capture is delayed, surface Processing explicitly and allow cancellation per airline policy.
  • On cancelling a split payment, route refunds correctly (wallet portion → wallet, card portion → original card).
  • Add server-side validation so an already-issued, confirmed PNR can never drop into a "Continue purchase" path.

The lesson

My takeaway from bug #1: the most valuable bugs aren't always the most technical — they're the ones where two systems disagree about reality. No payload, no exploit chain; just watching a money flow carefully and having the patience to check the card statement after the app said "success." Read the state machine, not just the request.

YL
Yasser LaroussiCPTS · eJPTv2
Next writeup
... /Related ...
Bug Bounty/Web · SSRF/Medium/6 min

Path traversal to a constrained SSRF: reading an internal Drupal host

A public content-listing endpoint accepted ../ sequences in a path parameter and relayed them to an internal Drupal backend, returning internal JSON the Internet can't reach. A redacted SSRF writeup.

WebBug BountySSRFDrupal
Read moreOct 2026
Bug Bounty/Android · Mobile/Hard/8 min

Hijacking a trusted app's WebView via an exported Android Activity

An energy app shipped a device-linking SDK whose Activity was exported with no permission, parsed an unsigned base64 token, and loaded attacker URLs into a JS-enabled WebView wired to native Bluetooth + OAuth bridges. A redacted writeup of an accepted finding.

MobileAndroidBug BountyWebView
Read moreOct 2026