IDOR in the Wild: A Comprehensive Analysis of 250 Real-World Vulnerabilities

IDOR in the Wild: A Comprehensive Analysis of 250 Real-World Vulnerabilities
๐ Executive Summary
Insecure Direct Object Reference (IDOR) remains the single most persistent authorization vulnerability in modern web applications. Through analysis of 250 disclosed IDOR reports from HackerOne spanning 2017โ2025, this study reveals that IDOR is neither rare nor declining โ it peaked at 50 reports in 2022 alone and continues at a rate of 30+ reports per year.
Our analysis exposes an uncomfortable truth: despite being conceptually simple (change an ID, access someone else's data), IDOR vulnerabilities have resulted in $129,408+ in disclosed bounties, with individual reports reaching $20,000. The real-world consequences go far beyond numbers โ from deleting any Snapchat creator's monetized content ($15,000) to stealing private GitLab projects including CI/CD secrets ($20,000) to adding unauthorized users to PayPal business accounts ($10,500).
What makes IDOR uniquely dangerous is its simplicity-to-impact ratio: a single parameter change can compromise an entire platform's authorization model. And unlike memory corruption or injection attacks, automated scanners rarely detect IDORs โ they hide in business logic, waiting for a human to notice that user_id=1234 can become user_id=1235.
๐ฏ What is IDOR?
Insecure Direct Object Reference occurs when applications expose direct references to internal objects (database IDs, file paths, user identifiers) without verifying that the requesting user is authorized to access them. Unlike complex exploitation chains, IDOR is often trivially exploitable โ change a number, access someone else's data.
# Your own profile
GET /api/users/1234/profile HTTP/1.1
Authorization: Bearer YOUR_TOKEN
# Attacker changes ID โ accesses someone else's data
GET /api/users/1235/profile HTTP/1.1
Authorization: Bearer YOUR_TOKEN
# Server returns victim's full profile โ no ownership check
๐ Analysis Methodology
This study examines 250 disclosed IDOR reports from HackerOne's Hacktivity, focusing on:
ANALYSIS SCOPE
- โข Temporal analysis: Trends from 2017โ2025
- โข Attack patterns: Direct ID, session misbinding, GraphQL, file access
- โข Industry sectors: Government, fintech, enterprise, social media
- โข Financial impact: Bounty distributions by severity
DATA SOURCES
- โข 250 HackerOne disclosed reports
- โข 50+ unique bug bounty programs
- โข 150+ unique security researchers
- โข CWE-639 classified vulnerabilities
๐ฅ Key Findings
1. Severity Distribution โ IDOR Hits Harder Than You Think
๐ SEVERITY BREAKDOWN (250 Reports)
Critical insight: 36.4% of IDOR vulnerabilities are rated High or Critical. The "IDOR = low severity" misconception costs organizations โ account takeovers, mass data theft, and financial fraud push severity upward significantly.
2. Temporal Trends โ IDOR Peaked in 2022, Still Strong
๐ YEAR-BY-YEAR DISTRIBUTION
3. Most Targeted Programs
๐ฏ TOP TARGETED ORGANIZATIONS
Key observation: The DoD leads with 28 reports โ government systems with legacy codebases are disproportionately affected. Meanwhile, GitLab's 11 reports include the two highest-bounty IDORs in the dataset ($20,000 each).
๐ฌ Attack Pattern Deep Dive
๐ฏ PATTERN 1: DIRECT ID MANIPULATION
Frequency: 45% of reports
Method: Change sequential/predictable IDs in URL or body
# Original request โ your booking
GET /api/v1/bookings/8847?token=abc123
# Attacker increments booking_id
GET /api/v1/bookings/8848?token=abc123
# Returns: victim name, phone, address, trip
Real Example โ Bykea (#2374730):
Exposed customer names, phone numbers, addresses, all trip details for any booking
โก PATTERN 2: SESSION MISBINDING
Severity: Critical โ highest avg bounty ($14K+)
Method: Valid auth token, no ownership check on target resource
POST /v1/account/destroy HTTP/1.1
Authorization: Bearer [ATTACKER_TOKEN]
Content-Type: application/json
{
"email": "victim@example.com",
"authPW": "deterministic_for_sso_users"
}
Mozilla (#3154983): $6,000 โ Delete ANY Firefox account (SSO users = email only)
๐ PATTERN 3: GRAPHQL ENUMERATION
Trend: Rising rapidly with API-first development
Method: Exploit GraphQL mutations lacking field-level authorization
mutation DeleteStorySnaps {
deleteStorySnaps(
ids: ["VICTIM_SNAP_ID"],
storyType: SPOTLIGHT_STORY
)
}
# Server deletes victim's monetized content
# No ownership check on snap ID
Snapchat (#1819832): $15,000 โ Delete anyone's Spotlight + kill their revenue
๐ PATTERN 4: FILE/DOCUMENT ACCESS
Risk: Extremely high in government/enterprise
Method: Enumerate file IDs in download endpoints
GET /Download.aspx?id=4675 HTTP/1.1
# Returns: military personnel document
GET /Download.aspx?id=4676 HTTP/1.1
# Returns: next document in sequence
# No authorization check on file ownership
DoD (#1626508): Military personnel documents exposed via sequential download IDs
๐ฆ PATTERN 5: IMPORT/EXPORT PIPELINE
Impact: Critical โ Cross-project data theft
Method: Craft malicious import files with foreign object IDs
// Crafted project.json inside tarball
{
"issue_ids": [27422144],
"issues": [],
"merge_request_ids": [99999]
}
// Import โ steals issues from other projects
GitLab (#743953): $20,000 โ Steal any project's issues, MRs, notes via crafted tarball import
๐ PATTERN 6: VULNERABILITY CHAINS
Complexity: Advanced โ multiple bugs combined
Method: Chain 2+ IDORs or IDOR + auth bypass for maximum impact
Chain: IDOR #1 โ enumerate voucher IDs
+ IDOR #2 โ modify voucher target
+ Auth bypass โ apply to any account
= Arbitrary charges to any business
Uber (#1145428): $5,750 โ 3-bug chain โ arbitrary charges to any U4B business credit card
๐ฅ Case Study Spotlight #1: GitLab Project Import โ $20,000
CASE STUDY: STEAL PRIVATE OBJECTS VIA PROJECT IMPORT
Report #743953 | Reporter: saltyyolk | Bounty: $20,000 ($1K initial + $19K bonus) | Severity: Critical
๐ฏ THE ATTACK
GitLab's project import feature accepts tarball archives containing a project.json file that defines the project structure. The researcher discovered that foreign key attributes like issue_ids, merge_request_ids, note_ids, and board_ids were not excluded during import processing.
By crafting a malicious tarball with one strategic modification:
{
"description": "Attacker's project",
"issue_ids": [27422144],
"issues": [],
"merge_request_ids": [12345678],
"merge_requests": []
}
The import process called @project.assign_attributes(project_params) in project_tree_restorer.rb, which blindly accepted these foreign key arrays. The result: issues, merge requests, notes, and boards from other projects were silently transferred to the attacker's project.
๐ฅ THE IMPACT
๐ง THE FIX & LESSONS
AttributeCleaner class now blocks all _ids assignments during import๐ฅ Case Study Spotlight #2: Snapchat Spotlight โ $15,000
CASE STUDY: DELETE ANYONE'S MONETIZED SPOTLIGHT CONTENT
Report #1819832 | Reporter: prickn9 (Sahil Saxena) | Bounty: $15,000 | Severity: High
๐ฏ THE ATTACK
Snapchat's Spotlight is the platform's answer to TikTok โ creators post short videos and earn money through "Crystal Awards" based on engagement. The researcher discovered that the GraphQL mutation for deleting Spotlight content had no ownership validation.
The attack was devastatingly simple:
POST /graphql HTTP/1.1
Content-Type: application/json
Cookie: [ATTACKER_SESSION]
{
"operationName": "DeleteStorySnaps",
"variables": {
"ids": ["VICTIM_SPOTLIGHT_VIDEO_ID"],
"storyType": "SPOTLIGHT_STORY"
},
"query": "mutation DeleteStorySnaps($ids: [String!]!, $storyType: StoryType!) {
deleteStorySnaps(ids: $ids, storyType: $storyType)
}"
}
The attacker simply intercepts their own deletion request in Burp Suite, replaces the ids array with the target victim's video ID, and forwards. The server never checks if the requesting user owns the content.
๐ฅ THE IMPACT โ BEYOND DATA
๐ง THE FIX
DeleteStorySnaps mutationPermissionDenied: unable to delete snap๐ฅ Case Study Spotlight #3: Mozilla Firefox โ $6,000 (The Escalation Story)
CASE STUDY: ACCOUNT DELETION VIA SESSION MISBINDING + SSO BYPASS
Report #3154983 | Reporter: z3phyrus | Bounty: $6,000 | Severity: High (initially closed as Informative!)
๐ฏ THE INITIAL FINDING
The Firefox Accounts API endpoint /v1/account/destroy accepted two parameters: email and authPW (password hash). The server validated that the credentials were correct โ but never checked that the authenticated session belonged to the account being deleted.
POST /v1/account/destroy HTTP/1.1
Authorization: Bearer [ATTACKER_SESSION_TOKEN]
Content-Type: application/json
{
"email": "victim@example.com",
"authPW": "42b4c2940fe2efecce851a2d8e9754d0f1cb1d37..."
}
Initially, Mozilla closed this as Informative: "If the attacker has the victim's email and password, this is not a vulnerability."
๐ THE ESCALATION โ SSO USERS HAVE NO PASSWORD
The researcher didn't give up. They discovered that SSO users (Google login) who never set a password share a deterministic authPW value. This meant:
Attack requirements for SSO users:
1. Know victim's email address โ trivial, often public
2. authPW is deterministic โ same for all SSO users without password
3. Use attacker's own session token
Result: Delete ANY Firefox Account of an SSO user
โ All synced bookmarks, passwords, history = GONE
The report was reopened, upgraded from Informative to High severity, and awarded $6,000.
๐ก THE META-LESSON
โ๏ธ The IDOR Kill Chain
๐ IDOR EXPLOITATION LIFECYCLE
Map the application's API surface. Identify endpoints that accept object identifiers: user_id, booking_id, document_id, order_id. Look for sequential integers, base64-encoded values, or UUIDs. GraphQL introspection reveals field-level identifiers.
Create 2+ accounts with different roles (user, admin, moderator). Document which objects each role can access. Note the IDs assigned to each account's resources โ this reveals the ID pattern (sequential, UUID, base64).
Use Account A's session to access Account B's resources. Test all CRUD operations: Can you read B's data? Update it? Delete it? Create resources under B's namespace? Each verb may have different authorization controls (or lack thereof).
If IDs are sequential, enumerate through ranges. Measure the blast radius: how many users/objects are accessible? For base64 IDs, decode and look for patterns. For UUIDs, check if they're leaked in other responses (search results, API responses, error messages).
Go beyond "I can see user #2's profile." Show the real impact: PII exposure (names, emails, phone numbers), financial data (invoices, payment details), write operations (account deletion, data manipulation). Document the chain from trivial access to critical business impact.
Write a clear PoC. If the initial assessment is low severity, look for escalation paths: Can you chain with another bug? Are there write operations? Does it affect financial/compliance data? The Mozilla report went from Informative to $6,000 through escalation.
๐งฑ Root Causes Analysis
โ ๏ธ PRIMARY ROOT CAUSE ANALYSIS
1. Missing Ownership Validation (78% of cases)
Authentication is present but ownership verification is absent. The server confirms "this is a valid user" but never asks "does this user own this resource?"
# VULNERABLE โ authenticates but doesn't authorize
@require_authentication
def get_booking(booking_id):
return database.get_booking_by_id(booking_id) # No ownership check!
# SECURE โ authenticates AND authorizes
@require_authentication
def get_booking(booking_id, current_user):
booking = database.get_booking_by_id(booking_id)
if booking.user_id != current_user.id:
raise PermissionDenied("Not your booking")
return booking
2. Predictable Object Identifiers (65% of cases)
Sequential integers, auto-incrementing database IDs, or easily decoded base64 values make enumeration trivial
// VULNERABLE โ Sequential IDs are trivially enumerable
const orderId = 1001; // Next order = 1002, 1003...
// BETTER โ UUIDs prevent enumeration (but still need ownership checks!)
const orderId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
// UUIDs are NOT a replacement for authorization โ they're defense-in-depth
3. Inconsistent Authorization Across Endpoints (45% of cases)
Some endpoints properly validate access while others โ often internal APIs, admin panels, or newer features โ are missed
# SECURE endpoint โ validates ownership
GET /api/users/profile โ Checks session ownership
# VULNERABLE endpoint โ same resource, different path
GET /api/users/{id}/orders โ Missing validation
GET /bugs.json?org_id={id} โ Search endpoint forgotten
4. Client-Side Only Security (23% of cases)
The frontend hides resources the user shouldn't see, but the API returns them anyway when asked directly
// VULNERABLE โ Client-side check only
if (currentUser.id === resourceOwnerId) {
showDeleteButton(); // Hidden โ Protected
}
// The API DELETE endpoint has no check at all
// Burp Suite bypasses this entirely
๐ญ Industry Impact Analysis
๐๏ธ GOVERNMENT & DEFENSE (28 reports)
- โข Military personnel data exposure
- โข Profile image deletion across systems
- โข Demographic data access via sequential IDs
- โข Document download without authorization
๐ฑ SOCIAL MEDIA (TikTok 17, Snap 5, Reddit 5)
- โข Content deletion / competitive sabotage
- โข Private video description access
- โข Support ticket enumeration
- โข DM deletion across accounts
๐ผ ENTERPRISE SOFTWARE (GitLab 11, LinkedIn 12)
- โข Private project object theft
- โข Cross-organization data access
- โข CI/CD secret compromise
- โข Profile and credential manipulation
๐ณ FINANCIAL SERVICES (PayPal, Stripe, Uber)
- โข Unauthorized user addition to business accounts
- โข Arbitrary charges to credit cards
- โข Billing document cross-tenant access
- โข Sale cancellation without authorization
๐ฐ Financial Impact Analysis
๐ต BOUNTY ECONOMICS
๐ TOP 10 IDOR BOUNTIES
๐ธ DIRECT COSTS
- โข Bounty payouts: $129K+ across 44 paid reports
- โข Incident response: $1.76M avg cost (IBM 2023)
- โข Regulatory fines: GDPR up to 4% of revenue
โ๏ธ OPERATIONAL IMPACT
- โข 82% of reports had no bounty โ responsible disclosure
- โข Avg resolution: 4.2 months to disclosure
- โข Gov systems: up to 14 months resolution time
๐ REPUTATIONAL DAMAGE
- โข 67% of users leave after a data breach
- โข Platform trust: HackerOne found IDORs in its own platform (17 reports)
- โข Competitive risk: Snapchat spotlight deletion = creator exodus
๐ก๏ธ Prevention Strategies
๐ DEFENSE PATTERNS THAT WORK
1. Centralized Authorization Middleware
# Authorization middleware โ ALL routes go through this
class OwnershipMiddleware:
def process_request(self, request, resource_type, resource_id):
resource = get_resource(resource_type, resource_id)
if resource.owner_id != request.user.id:
if not request.user.has_role('admin'):
raise PermissionDenied(
f"User {request.user.id} cannot access "
f"{resource_type}/{resource_id}"
)
# Audit log every access
audit_log(request.user.id, resource_type, resource_id, 'access')
2. Scope Queries to Current User (Query-Level Defense)
# VULNERABLE โ fetches any booking then checks
booking = Booking.objects.get(id=booking_id)
if booking.user != request.user: raise PermissionDenied()
# SECURE โ query is scoped from the start
booking = Booking.objects.get(id=booking_id, user=request.user)
# If user doesn't own it โ DoesNotExist โ 404
# No IDOR possible โ the query itself enforces ownership
3. Resource-Based Access Control (RBAC)
# Policy definition
resource: booking
actions: [read, update, delete]
rules:
- condition: resource.user_id == request.user.id
effect: allow
- condition: request.user.role == 'admin'
effect: allow
- default: deny
4. What DOESN'T Fix IDOR
๐งช Bug Hunter Methodology
๐ ๏ธ SYSTEMATIC IDOR HUNTING GUIDE
Step 1: Setup โ Two Accounts Minimum
Create Account A (attacker) and Account B (victim). Different roles if possible: regular user, admin, moderator. Note the IDs assigned to each account's resources.
Step 2: Map Every Endpoint
Use Burp Suite to spider the app. Export the sitemap. Search for any parameter that looks like an ID: id, user_id, uid, profile_id, booking_id, order_id, doc_id. Check request body, URL path, query params, and headers.
Step 3: Test All 4 CRUD Operations
For each identified ID parameter, test with Account A's token but Account B's resource ID:
- GET โ Can you read B's data?
- PUT/PATCH โ Can you modify B's data?
- DELETE โ Can you delete B's resources?
- POST โ Can you create resources under B's namespace?
Step 4: Check Non-Obvious Surfaces
- โข GraphQL: Check mutations AND queries โ use introspection to find hidden fields
- โข Import/Export: Craft malicious import files with foreign IDs (GitLab pattern)
- โข Webhooks & Callbacks: Often skip authorization entirely
- โข Search endpoints:
/search?org_id=Xmay bypass normal access controls - โข Admin panels: Internal tools often have weaker checks
- โข Mobile APIs: Older versions may lack authorization middleware
๐ IDOR TESTING CHECKLIST
๐ฅ IDOR PARAMETER CHEATSHEET
# High-value parameter names to test
user_id, id, uid, user, profile_id, account_id, member_id
booking_id, order_id, transaction_id, payment_id, invoice_id
document_id, file_id, attachment_id, media_id, asset_id
project_id, org_id, team_id, workspace_id, tenant_id
report_id, ticket_id, case_id, issue_id, request_id
comment_id, note_id, message_id, thread_id, conversation_id
certification_id, license_id, credential_id, badge_id
# GraphQL-specific patterns
node(id: "base64_encoded_global_id")
mutation { deleteResource(id: "VICTIM_ID") }
query { user(id: VICTIM_INT) { privateField } }
# Encoded ID patterns to decode
base64: eyJ1c2VyX2lkIjoxMjM0fQ== โ {"user_id": 1234}
hex: 0x4D2 โ 1234
uuid: check if sequential or truly random
๐ฅ Researcher & Geographic Patterns
๐ TOP IDOR HUNTERS
Notable: @jobert (HackerOne co-founder) leads with 7 โ many found on HackerOne's own platform. @bugbountywithmarco specializes in ride-sharing/transportation IDORs.
๐ RESEARCHER DEMOGRAPHICS
๐ฎ Future Trends and Emerging Threats
โ ๏ธ EMERGING IDOR THREAT LANDSCAPE
1. GraphQL & API-First Architectures
GraphQL's flexibility is a double-edged sword. Nested queries can access multiple resources in a single request, and field-level authorization is harder to enforce than endpoint-level controls. Our data shows GraphQL IDOR reports are increasing year over year.
Trend: 2020-2022 saw 5 GraphQL IDORs; 2023-2025 saw 12+ โ a 140% increase
2. Microservices Authorization Gaps
In microservices architectures, each service may implement its own authorization logic (or forget to). API gateways validate authentication but often pass through resource IDs without ownership checks. Service-to-service communication frequently runs with elevated privileges.
Example: Uber's 3-bug chain exploited gaps between voucher, payment, and business services
3. AI-Powered Applications
AI assistants that access user data create new IDOR surfaces. If a chatbot can query user orders, can it be tricked into querying other users' orders? MCP (Model Context Protocol) servers that interact with APIs on behalf of users introduce tool-based IDOR vectors.
Risk: AI tool calls may bypass traditional authorization middleware entirely
4. Mobile App API Divergence
Mobile apps often use different API versions than web apps. Legacy mobile API endpoints may lack authorization updates applied to the web version. Reverse engineering mobile apps reveals hardcoded or zombie endpoints (like Bykea's unused but still accessible endpoints).
Example: Bykea #3085742 โ IDOR on hardcoded zombie endpoint found via Android app reverse engineering
๐ข Recommendations for Organizations
๐จ IMMEDIATE ACTIONS (0-30 days)
- 1. Audit all API endpoints for ownership validation โ prioritize write operations (DELETE, PUT)
- 2. Implement query scoping โ add
WHERE user_id = current_userto all resource queries - 3. Review GraphQL schema for mutations lacking field-level authorization
- 4. Add audit logging for all resource access attempts (detect enumeration)
โก MEDIUM-TERM (1-6 months)
- 1. Deploy centralized authorization middleware โ make ownership checks automatic, not optional
- 2. Replace sequential IDs with UUIDs for all external-facing identifiers
- 3. Add IDOR-specific tests to CI/CD โ automated cross-account access testing
- 4. Conduct import/export audit โ verify all bulk operations validate ownership
๐ฏ LONG-TERM (6+ months)
- 1. Adopt policy-as-code โ define authorization rules in declarative policies (OPA/Rego)
- 2. Security champions program โ embed access-control expertise in every team
- 3. Regular red team exercises specifically targeting authorization boundaries
- 4. Multi-tenant architecture review โ ensure complete data isolation between tenants
๐ฏ Conclusion
๐ FINAL ANALYSIS
IDOR is the vulnerability class that refuses to die. Our analysis of 250 HackerOne reports spanning 2017-2025 reveals a persistent, endemic problem: despite being one of the simplest vulnerability concepts to understand, IDOR continues to affect platforms of every size and industry at a rate of 30+ disclosed reports per year.
Key Takeaways:
- 1. IDOR is NOT low severity: 36.4% of reports are High/Critical. The average critical-severity IDOR bounty is $14,333 โ this is a serious bug class.
- 2. Write operations are the real danger: The $20K GitLab, $15K Snapchat, and $6K Mozilla reports all involved write/delete operations โ not just data reads.
- 3. Non-obvious attack surfaces exist: Import/export pipelines, GraphQL mutations, zombie mobile endpoints, and search features are frequently missed by developers.
- 4. The fix is engineering, not tooling: No scanner reliably detects IDOR. Centralized authorization middleware with query-level scoping is the only systemic solution.
- 5. Persistence wins for hunters: The Mozilla report went from "Informative" to $6,000 through escalation research. Never accept the first triage decision.
The Path Forward:
The most effective defense against IDOR is not a tool or a checklist โ it's an architectural decision. Scope every database query to the current user. Make authorization middleware mandatory, not optional. Treat every object identifier as untrusted input. The organizations that systematically enforce these patterns see their IDOR report rates drop to near zero. The rest continue to pay bounties.
For Bug Hunters:
IDOR remains one of the most accessible and rewarding vulnerability classes to hunt. The key to higher bounties: don't stop at proving access. Show the blast radius โ how many users are affected? Can you write, not just read? Does it chain with another bug? The difference between a $500 and a $20,000 IDOR report is the impact you demonstrate.
This analysis is based on 250 publicly disclosed IDOR vulnerability reports from HackerOne, spanning 50+ unique bug bounty programs from 2017 to 2025. It represents a subset of actual IDOR vulnerabilities โ many findings remain undisclosed or were reported through private programs.
This research was mainly conducted with the assistance of AI to enhance clarity and structure.