Bug Hunting Journey

Writeups IDOR

IDOR

Sequential invoice IDs, and no check at all

Severity Medium CVSS 6.5
Impact
Billing details and contact names of other customers
Bounty
under $500
Program
Private

TL;DR

Invoice PDFs were served by a sequential integer with no ownership check. Any authenticated user could walk the range and read every invoice issued by the platform.

Not every finding is clever. This one took four minutes, and it is worth publishing precisely because it still exists in 2026 on a product that bills real companies.

The whole thing

GETMy own invoicerequest
GET /billing/invoices/80422/pdf HTTP/2Host: app.target.tldCookie: session=████████████████

Decrement by one:

200OKresponse
HTTP/2 200 OKcontent-type: application/pdfcontent-disposition: inline; filename="INV-80421.pdf"

A PDF belonging to a different company, with its legal name, billing address, contact email and line items. No 403, no ownership check, no rate limit. I read three invoices to establish the pattern, confirmed they were not mine, and stopped.

Why it survived

The invoice route was added before the platform grew an authorisation layer, and it sits in an older router that the newer middleware never got mounted on. Nothing in the code looks wrong when you read that file on its own, which is exactly why reading a single file is not a review.

Takeaways

  • Try the boring thing first. Sequential identifiers in a URL are still the fastest finding in the book.
  • Authorisation middleware applied per router is authorisation you will forget to mount. Default to deny at the framework level.
  • Stop at three. You only need enough to prove the pattern, and every extra record is someone’s real data.

Disclosure timeline

  1. Report sent
  2. Triaged
  3. Fix deployed
  4. Cleared for publication