← Back to all reports

Race Condition Turns $10 Gift Card into $365

Reported Mar 16, 2026
Severity Critical
Platform Android
Vulnerability Class Race Condition (CWE-362)
Target Type Cinema / Entertainment
Reproduction Rate 4 out of 4 attempts

The Risk

A cinema chain's refund system could be tricked into crediting a gift card multiple times for a single ticket refund. A $5 ticket refund generated $90-100 in gift card credit each time, turning a $10 gift card into $365 over four tests. The gift card balance could be spent at any location in the chain, and anyone who downloaded the app had everything they needed to reproduce this.

The Vulnerability

The vulnerability chain started with the Android APK. Reverse engineering revealed all the credentials needed to interact with the booking API:

  • An API token stored in plaintext in res/raw/local_config.json
  • An HMAC signing key encrypted with AES-256 in res/values/strings.xml, with the AES key hardcoded in the Java source

With these credentials, it was possible to authenticate as any loyalty member and interact with the booking API directly, bypassing the app entirely.

The Attack

The refund flow worked like this:

  1. App sends POST /refund with booking ID and gift card number
  2. Application server checks: "Has this booking already been refunded?"
  3. If not, it forwards the credit to the downstream payment server
  4. Payment server credits the gift card and returns success
  5. Application server marks the booking as refunded

The problem: steps 2 and 5 are not atomic. When 20 requests arrive simultaneously, multiple pass the check at step 2 before any of them reach step 5. The payment server processes each credit independently.

Reproduction

The PoC script authenticated via the loyalty API using HMAC-signed headers, then fired 20 concurrent refund requests using a thread pool. Each request had independently generated HMAC signatures with unique request IDs.

The server responses broke down consistently across all four tests:

ResponseCountMeaning
HTTP 200 + booking data1-2Refund officially processed
HTTP 500 "RefundAlreadyInProgress"~6Passed validation, credit likely committed
HTTP 400 "already refunded"~13Lock took effect, rejected

The HTTP 500 responses are the key indicator. They prove the request passed application validation and reached the payment server before the lock. Each one results in a gift card credit.

The Impact

TestBeforeAfterGainMultiplier
1$0.20$95.20+$95.0019x
2$88.60$178.60+$90.0018x
3$172.00$272.00+$100.0020x
4$265.40$365.40+$100.0020x

Each cycle cost ~$6.60 (one bargain ticket + booking fee) and returned $90-100 in gift card credit. The gift card balance could be used at any location in the cinema chain.

Why Mobile Matters Here

This vulnerability wouldn't have been found through web testing alone. The API credentials were embedded in the APK. The HMAC signing key was encrypted with AES, but the AES key was in the decompiled Java source. Without reversing the app, there's no way to authenticate with the booking API independently.

The race condition itself is a classic server-side flaw, but the attack surface was only accessible through the mobile app's API.

Remediation

  • Implement atomic locking on refunds at the database level (e.g., SELECT FOR UPDATE or advisory locks)
  • Add server-generated idempotency keys that reject duplicate refund attempts
  • Validate at the payment server level that total credits never exceed the original transaction amount
  • Rotate the hardcoded API credentials and move to server-issued short-lived tokens
  • Audit gift card balances for anomalous credit patterns

Responsible Testing

The gift card was purchased with personal funds ($10). The program was asked to disable and zero out the card after testing. No real customers were affected.