One Vendor Number, the Whole Directory — Then the Keys
The app identified vendors by a number in the request. Read anyone's profile with it; then change their email and own the account.
Target anonymized · a global retailer's vendor portal
Some findings are one bug. This was one broken idea — "trust the vendor number in the request" — expressed in two endpoints, and together they went from information disclosure to full account takeover.
The spark
Every request the portal made carried a "vendor number" identifying whose data to load. Mine looked sequential. Whenever an app hands the client the identifier that decides whose record to serve, I stop and pull the thread.
Digging in
Read first. I changed the vendor number on a profile-fetch request to a neighbouring value and got back a different company's full business profile: legal name, contact person, email, phone, category. No ownership check, and — crucially — no rate limiting. So this wasn't just "read one stranger"; it was "enumerate the entire vendor directory."
Then the obvious escalation: if reads aren't authorised, are writes?
Write next. The profile-update request carried the same number. I set it to a victim's value and changed the email address on their account. The server accepted it.
Once you can set a victim's account email, you don't need their password — you ask the site to reset it for you.
The exploit
The chain, with two test accounts I controlled:
- Update-profile request, vendor number set to the victim,
emailset to mine →200 OK. - Trigger the standard password reset → the reset link lands in my inbox.
- Reset, log in. The account is mine. The victim did nothing.
Impact
Two impacts stacked: mass harvesting of every vendor's business PII by enumeration, and a zero-interaction account takeover of any vendor. Either one is serious; together they're critical.
The fix
Derive the vendor context from the authenticated session, never from a number in the request. Authorize reads and writes against that principal, and rate-limit the lookup so enumeration isn't free.
All identifiers, targets and payloads in this post are anonymized or defanged. Findings were reported and resolved through responsible disclosure.