← Back to all reports

Booking Reference Lookup Exposes Other Suppliers' Traveller Data

Reported Jun 22, 2026
Severity High
Platform Web
Vulnerability Class Insecure Direct Object Reference (CWE-639)
Target Type Travel / Tours Marketplace
Impact Cross-supplier traveller data harvest

The Risk

Anyone could sign up for a free supplier account on this travel marketplace and read the bookings of every other supplier on the platform. Typing a booking number into the search box returned the customer's name, the tour they bought, their travel date, where they were being picked up, and the price paid, even when that booking belonged to a completely different business. The booking numbers run in a simple sequence, so a single free account could walk through them one after another and harvest years of traveller records, with no victim ever doing anything. Roughly one in three of those guessed numbers returned a real stranger's booking.

The Vulnerability

The supplier portal lets each tour operator look up their own bookings by reference number through a search box on the Bookings page. The reference format is a fixed prefix followed by a run of digits, and those digits increase over time, so references are effectively sequential and guessable.

The flaw is a missing ownership check. When the portal resolved a reference to a booking, it never verified that the booking actually belonged to the supplier making the request. A brand-new account that owned zero bookings of its own could enter any reference and receive the full booking record for it, regardless of which supplier created that booking.

This was not a quirk of the search box. The same authorization gap existed on the underlying record-fetch request and on the action-preflight request that the portal used before offering booking operations. A reference the caller did not own returned a complete record on multiple endpoints; only a non-existent reference was rejected.

What the record exposed

Each leaked booking returned the traveller's name, age band, an internal traveller identifier, the product booked, the travel date, the number of travellers, the pickup location, the net price, the booking source, language, and status. Contact details were more limited: there was no email field, the phone number was suppressed, and the optional travel-information block (date of birth, passport, flight details) was empty on every record sampled. So the exposure was a cross-supplier read of traveller names and trip metadata, not contact numbers or identity documents.

The Attack

Reproduction from the browser

The core issue reproduced in a normal browser with no developer tools or scripting:

  1. Register a free supplier account through the standard self-service signup. No products, no bookings, and no account verification are needed.
  2. Log in and open the Bookings page. The account shows the supplier name in the header and clearly owns no bookings of its own.
  3. Type any booking reference into the search box and run the search. The portal renders the full booking card for that reference, which belongs to another supplier.
  4. Repeat with any other reference to read a different supplier's customer.

Enumeration at scale

Because references are sequential and the search box accepts any value, an attacker does not need to know victim references in advance. Walking a contiguous block of references in the dense historical range returned a valid foreign booking roughly one in three attempts. Confirming the same reference directly against the record-fetch request returned a full record for references the caller did not own, while an unknown reference returned an access-denied response. The same behaviour held on the action-preflight request, confirming the missing tenant check was server-side and spanned more than one endpoint, not a single UI bug.

A per-booking ownership check appears to have been partially rolled out at some point, because the dense readable set is concentrated in the older historical backlog. Enforcement was inconsistent rather than a clean cutoff, though: a fraction of current, future-dated bookings still leaked, so live customer data was exposed, not only history.

The Impact

A single low-privilege account that owned nothing could read other suppliers' customer bookings across many years and many countries. Confirmed cross-supplier reads spanned travellers across multiple continents on a range of tours, all read by an account that held zero bookings of its own.

The exposed data is traveller names plus trip metadata: who is travelling, on what tour, on what date, from which pickup point, and at what price. That is enough to support convincing targeted phishing and impersonation of either the traveller or the operator, and it is a privacy breach of customer records belonging to thousands of independent businesses on the platform.

The impact was bounded by what the records did not contain and what could not be changed. No email addresses or phone numbers were returned, and every readable booking reported that it could not be cancelled or modified, so cancel, no-show, and refund actions could not be exercised across suppliers. The finding is a large-scale cross-tenant read, not booking tampering.

Remediation

  • Enforce a per-booking ownership check on every read path. A supplier requesting a reference it does not own should receive no result or an access-denied response, never the record.
  • Apply the same check uniformly across the search endpoint, the record-fetch endpoint, and the action-preflight endpoint. Fixing only the visible search box leaves the others exploitable.
  • Treat sequential, guessable reference numbers as enumerable identifiers. Authorization is the real control, but adding rate limiting and anomaly detection on reference lookups raises the cost of bulk harvesting.
  • Audit access logs for accounts that resolved large numbers of references they do not own, and assess notification obligations for the exposed historical records.