Finding an IDOR That the Web Testers Missed
Richard · January 18, 2026
A target I tested had already been through two rounds of web app testing. The web client was solid — object-level authorization was enforced consistently across every endpoint the browser touched. The mobile app, though, had never been in scope for either engagement.
Same backend, different client, different endpoints
The assumption on a lot of programs is that “the API” is a single surface, and if the web app is locked down, the API is locked down. That’s rarely true. Mobile clients frequently hit endpoints the web app never calls — bulk sync routes, background refresh calls, legacy versions kept alive for older app builds still in the wild.
Pulling the Android app’s traffic through a proxy turned up exactly that: a
/v1/sync/user-documents endpoint the web client had no code path to reach
at all. It existed purely to let the mobile app batch-fetch a user’s
documents on launch.
The actual bug
The endpoint took a userId parameter and returned that user’s documents.
Swapping in another user’s numeric ID returned their documents too — no
ownership check against the authenticated session. Textbook IDOR, but only
reachable through a request shape the web testers never had a reason to
construct, because the browser client never sent it.
POST /v1/sync/user-documents
{
"userId": 10482,
"since": 0
}
Changing userId to a sequential neighbor returned a different user’s full
document set, no additional auth check anywhere in the response path.
Why this matters for how you test
If you’re used to testing web apps, it’s natural to assume the API surface is whatever the browser’s network tab shows you. On a target with a mobile client, that assumption leaves an entire class of endpoints untested. The lesson isn’t “IDORs are common” — everyone already knows that. It’s that the reachable surface is different per client, and skipping the mobile app means skipping endpoints that may never have been reviewed by anyone.