BUSINESS LOGIC // PAYMENT BYPASS // MEMBERSHIP ABUSE
WEB APPLICATION SECURITY

Free Diamond Memberships: Payment Logic vs Encrypted Add-On APIs

HOTEL B2B // AES BODY CRYPTO // ADD-ON FLOW

researcher
Naveen Jagadeesan
published
2023-10-31
platform
Hotel Booking / Subscription Platform

Summary

A B2B hotel reservation platform sold tiered memberships (Silver → Diamond) with booking discounts and loyalty multipliers. API bodies were AES-encrypted in the browser, which slowed casual testing — but not analysis. After recovering keys from shared JS, manipulating payment method selectors and membership flags activated Diamond benefits without a successful membership payment.

Why this is more than “change price to 0”

Classic price tampering was partially mitigated elsewhere in the industry narrative. Here the interesting failure is workflow desynchronization:

Payment completion and entitlement activation were not the same server-side transaction.
The client could still assert membership state inside “encrypted” add-on calls.

Crypto friction made the bug look advanced; the root cause is ordinary business-logic.

Stack & friction

Reversing enough crypto to test logic

Bundles exposed domains, keys, IVs, and encrypt/decrypt helpers (same class of issue as other portfolio apps). Payload framing resembled:

Base64Ciphertext + "---" + Base64(IV)

With offline decrypt/encrypt, Burp became useful again: read real JSON, mutate, re-seal.

Membership purchase flow

High-level:

  1. User selects Diamond (or similar) during booking.
  2. Client calls membership add API with encrypted body.
  3. Client calls purchase/add-on API with payment metadata.
  4. Backend should: charge → verify → activate entitlements.

Observed sensitive fields after decrypt (simplified):

{
  "user_club_membership_id": 123456,
  "diamond_club": true,
  "payment_method": 26
}

Exploit theory

Probe enums around payment_method while keeping entitlement flags true:

Result

Changing payment_method from the premium path value to an alternate internal code removed the additional membership charge while membership activation parameters remained present. Backend still applied:

Payment was not a hard prerequisite for entitlement.

Impact

Root causes

Fixes

  1. Server-side state machine: PAYMENT_CAPTURED → ENTITLEMENT_GRANT only.
  2. Ignore client diamond_club assertions; derive tier from paid invoices.
  3. Idempotent server records linking payment_intentmembership_id.
  4. Remove long-term symmetric keys from clients (see crypto writeup).
  5. Monitor activations without matching settlement events.

Takeaway

Encrypting a broken workflow yields an encrypted broken workflow. Once you can read the JSON, test whether money movement and privilege grants are inseparable — that is where the real bugs hide.