I'm always excited to connect with professionals, collaborate on cybersecurity projects, or share insights.

Social Links

Status
Loading...
Bug Bounty

How I Found IDORs That Shouldn’t Exist

How I Found IDORs That Shouldn’t Exist

Imagine you’re testing a major program. You poke one endpoint and, suddenly, you can see customer data you absolutely shouldn’t. Not because of a flashy payload - because of sloppy access control logic.

That’s IDOR territory. Not the classroom version, but real-world IDORs that lead to account takeover, data exposure, or worse. This article skips definitions and goes straight to the tools and tricks that find impact in live targets.

IDORs are everywhere

CRMs, e-commerce, project trackers, BI dashboards, healthcare portals - any app built around users, objects, or lists can contain IDORs. The question isn’t if they exist - it’s where they hide. That means your hunting starts with mapping the app’s data surface (APIs, list endpoints, profile pages), not blind ID flipping.

How to think about it

Novice approach: change id=10 to id=9 and hope for a popup.
Pro approach: ask what the endpoint assumes, how it’s parsed, and how different layers (router, proxy, app, cache) normalize requests.

Shift your question from “Can I change this number?” to:

  • Which controller handles this path?
  • Is there a separate endpoint that bypasses the same check?
  • Does the app accept alternate formats (strings, encoded chars, different versions)?

That mental model is the difference between a noisy scan and a real find.

Example context & assumptions

  • Assume your user ID = 100.
  • Endpoint we see:

    /api/v5/users/100
  • For another user 99 you get 403 - normal. But that 403 is the starting point, not the end.

Below are the practical techniques I run, in order (from cheap/noise to the deeper ones).

The techniques (what to try - with examples)

Rule: keep tests low-noise, log every request/response pair (status + path) and redact values you can’t show publicly.

 

1) Trailing slash / path normalization

Some auth checks run on normalized paths but others don’t.

/api/v5/users/100       → 200
/api/v5/users/99        → 403
/api/v5/users/99/       → 200

Try adding/removing trailing slashes.

 

2) Double-slash or obfuscated path

Routers and proxies sometimes collapse or ignore duplicate separators.

/api/v5/users/99        → 403
/api/v5//users//99      → 200

Double slashes, /., //. variations - quick to test.

 

3) Version downgrade (legacy endpoints)

Older API versions may miss modern checks.

/api/v5/users/99        → 403
/api/v2/users/99        → 200

Try v4, v3, v2 - especially on apps that keep multiple API versions.

 

4) Subpath / endpoint variant (profile / details)

Different controllers sometimes apply inconsistent rules.

/api/v5/users/99/profile    → 200
/api/v5/users/99/details    → 200

Check /profile, /details, /info, /summary variants.

 

5) Multi-ID / filter parameter abuse

List endpoints that accept filters or multi-IDs can leak others.

/api/v5/users?where=id:100,99   → returns both records

Try comma lists, where filters, ids[]=…, etc.

 

6) Query param vs path

Same resource accessible through different routes with different checks.

/api/v5/users/99           → 403
/api/v5/users?id=99        → 200

Test id in path vs query string.

 

7) Type confusion - string vs integer

Different parsing code paths may treat types differently.

/api/v5/users/99           → 403
/api/v5/users/"99"         → 200
/api/v5/users/abc99        → 200

Try quoting numbers, adding alpha prefixes, or sending JSON body IDs instead.

 

8) Leading zeros / hex / alternate formats

Numeric parsing quirks can be abused.

/api/v5/projects/099       → 200
/api/v5/projects/0x63      → 200

Test 099, 0xNN, 0NNN forms where applicable.

 

9) NULL / termination / control characters (%00)

Some parsers don’t expect control chars and end up truncating or ignoring trailing validation.

/api/v5/projects/99%00     → 200

Null byte (%00) and other control encodings can bypass checks when not properly sanitized.

 

10) Header / proxy-based bypass (X-Original-URL / X-Forwarded-For)

Reverse proxies sometimes forward headers that alter internal routing or auth decisions. Test carefully and within program rules.

GET /api/v5/admin/99
Host: target
X-Original-URL: /api/v5/admin/100
→ returns 200 (if proxy honored header)

Caution: header tests can be noisy; know program policy and keep it passive.

 

11) Unicode / encoded-space trick - the deep/winner technique

This is the one that repeatedly gave me real, high-impact bugs. It’s simple: introduce an encoded space (%20) or subtle encoded character around the ID so different layers normalize it differently.

/api/v1/projects/99       → 403
/api/v1/projects/99%20    → 200   ← the hit

Variants to try: %20 before the ID, trailing %20, %20/, %09, combined with version downgrade or trailing slashes.

This trick works because one layer sees 99%20 as 99 (with a trailing space) and another layer strips/normalizes it differently - effectively sidestepping the auth hook.

 

12) Composite / chained variants

If a single trick fails, combine two or three:

/api/v2/projects/99%20/   → 200

Downgrade + encoded char + path tweak = often effective.

 

Quick recap - checklist to copy in your notes

  • Find the JSON/API endpoints (not the rendered HTML) - that’s your surface.
  • Try cheap, low-noise tweaks first: trailing slash, double slash, subpaths, query params.
  • Test version downgrades - old APIs are gold.
  • Try type/format tricks: strings, leading zeros, hex.
  • Try encoding tricks: %00, %20, control chars.
  • Combine tricks when single tests fail.
  • Log request + response (status + body snippet) - that becomes your PoC.

 

Outro

This is tactical work: small tweaks, methodical testing, and the right mindset. A boring 403 isn’t an obstacle - it’s a diagnosis. Ask the right questions, test the right angles, and you’ll stop getting noise and start finding impact.

If you want more tactical breakdowns (short, focused, practical), tell me which area: API logic, CORS chains, file uploads, or something else - and I’ll dig one up. I read every comment.

If you have questions, leave them below or ping me on Twitter.

5 min read
Oct 12, 2025
By Amr Elsagaei
Share

Leave a comment

Your email address will not be published. Required fields are marked *

Related posts

Oct 15, 2025 • 5 min read
The TrashCash | Turning Deleted Files Into Bounties
Oct 01, 2025 • 5 min read
All You Need to Start Bug Bounty. The 3 Essentials
Sep 13, 2025 • 5 min read
Hacking HubSpot | Live Bug Bounty Hunting
Your experience on this site will be improved by allowing cookies. Cookie Policy