As a security researcher, I've learned that assumptions like this are often where vulnerabilities hide.
This post is about how I discovered an Insecure Direct Object Reference (IDOR) that allowed unauthorized access to unpublished (draft) resources — and why this class of bugs is still surprisingly common.
⚠️ All identifiers, domains, and target details have been intentionally anonymized.
What Is IDOR (Quick Refresher)
An IDOR occurs when an application:
- Uses a direct reference (like an ID number) to an object
- Fails to properly verify ownership or authorization
- Allows an attacker to access or modify someone else's data
In short:
"If you know the ID, you can access the object — even if it's not yours."
The Context
The target application allows users to create listings. These listings can exist in two states:
- Published → visible to others
- Draft (unpublished) → visible only to the owner
Or at least… that's how it's supposed to work.
Each listing also has a messaging feature, allowing users to communicate about a listing.
That's where things got interesting.
The Assumption That Broke Everything
The application assumed:
"If a listing is unpublished, nobody else can interact with it."
But assumptions don't enforce security — authorization checks do.
I noticed that the backend API accepted requests like:
/api/listings/{LISTING_ID}/conversationsAt first glance, this looked normal. But one question mattered more than anything else:
Does the server verify that I'm allowed to access this listing ID?
Testing the Boundary
To test this safely, I used two accounts:
- Victim account → creates a listing and keeps it as a draft
- Attacker account → completely unrelated user
From the victim account, I:
- Created a listing
- Left it unpublished
- Noted the listing ID from the URL
Then, from the attacker account, I:
- Sent a request to the conversations endpoint
- Replaced my own listing ID with the victim's draft listing ID

No tricks. No race conditions. No special headers.
Just… a different ID.
The Result
The request succeeded.

As the attacker, I was able to:
- ✅ Access details of an unpublished listing
- ✅ Send messages to that draft listing
- ❌ Without being the owner
- ❌ Without any authorization error
At that moment, the issue was clear:
Draft did not mean private.
Why This Matters
Unpublished resources often contain:
- Incomplete data
- Personal information
- Pricing or internal notes
- Content the owner explicitly chose not to make public
This vulnerability allowed unauthorized access to private user data, which makes it a high-impact IDOR, not a cosmetic or edge-case bug.
Root Cause (In Simple Terms)
The backend validated:
- ✔️ "Is the user authenticated?"
But failed to validate:
- ❌ "Does this user own or have access to this specific object?"
This is one of the most classic — and dangerous — authorization mistakes.
Lessons for Developers
If you build APIs, especially RESTful ones:
- Never trust object IDs from the client
- Always enforce object-level authorization
- Treat draft, private, and unpublished data as highly sensitive
- Test endpoints with cross-account access, not just happy paths
Lessons for Security Researchers
If you're hunting for IDORs:
- Look for numeric or predictable IDs
- Focus on draft, private, or hidden resources
- Test actions beyond "view" — like messaging, updating, or triggering workflows
IDORs aren't flashy, but they're everywhere — and companies do care about them when demonstrated clearly.
Final Thoughts
This bug didn't require:
- Advanced exploitation
- Bypassing authentication
- Chaining vulnerabilities
It only required asking one question:
"What happens if I access something that isn't mine?"
Sometimes, that's all it takes.