Axeploit
← Back to posts

IDOR at Scale: Why One Broken Object Reference Can Mean a Full Customer Data Leak

By Pallavi M

IDOR Insecure Direct Object Reference sounds like a contained problem. The name suggests one thing: a reference to an object, which is insecure, which therefore exposes that object. One object. One exposure. One record.

The name is misleading in a specific and important way. In a multi-tenant SaaS application, a single IDOR vulnerability is rarely a one-record problem. It is almost always an everyone's-records problem — because the same code path that returns one unauthorized record will, given a different identifier, return any record in the system. The vulnerability is in the logic, not in the data. The logic applies to every request, not only to the one where it was first discovered.

This is the scale problem that makes IDOR one of the most consequential vulnerability classes in production SaaS applications. A single broken authorization check, applied uniformly across an endpoint that serves every customer's data, means the entire customer dataset is accessible to anyone who can authenticate to the platform and modify an identifier in a request.

Not one customer's data. Every customer's data. In sequence. Automatically. Without triggering any alarm that was designed to catch something breaking.

The Anatomy of an IDOR Vulnerability

Before the scale problem, the mechanism.

IDOR occurs when an application uses a direct reference to an internal object a database primary key, a document ID, a user identifier in an API endpoint, and the application does not verify that the requesting user is authorized to access the object referenced by that identifier.

The simplest form:

GET /api/documents/4821

Authorization: Bearer <user_A_token>

The server receives this request. It validates the token user A is authenticated. It fetches document 4821. It returns document 4821. What it did not do: verify that document 4821 belongs to user A.

If document 4821 belongs to user B, user A received user B's document. If user A modifies the identifier to 4822, 4823, 4824 any other identifier in the system they receive those documents too. Every document, belonging to every user, accessible to any authenticated user who can change a number in a URL.

The authorization check that would have prevented this:

One comparison. Three lines of code. The absence of those three lines means the endpoint has no authorization.

Why Multi-Tenant SaaS Makes IDOR Exponentially Worse

In a single-user application, an IDOR vulnerability exposing another user's data has limited scope there may be only one other user. In a two-company deployment, it exposes one other company's data. In a multi-tenant SaaS platform with five hundred enterprise customers and fifty thousand end users, a single IDOR vulnerability in a document management endpoint exposes five hundred companies' documents and fifty thousand users' data.

The math is not additive. The attacker does not need to find five hundred separate vulnerabilities to access five hundred companies' data. They find one. The one IDOR in the document endpoint applies equally to every document in the system. The authorization check is absent from the code path, and the code path serves every tenant.

This is the architecture of the exposure. Multi-tenant SaaS is explicitly designed so that one codebase serves all customers. One API endpoint serves all customers. One query serves all customers filtered by the authenticated user's identity. An IDOR vulnerability removes that filter. The query still runs. The data still returns. The filter was the only thing separating one customer's data from another's.

The Enumeration Problem: From One Record to All Records

The transition from "one IDOR" to "full data leak" depends on how object identifiers are structured. This is where the practical impact of a single IDOR finding gets determined.

Sequential integer IDs. The most dangerous configuration from an enumeration perspective. If documents are identified by integers and they are assigned sequentially, an attacker who discovers IDOR on document 4821 can enumerate the entire document collection by iterating: 4820, 4819, 4818... and 4822, 4823, 4824.... The entire dataset is accessible through sequential iteration. No guessing required. The attacker can write a loop.

UUIDs but predictable ones. Version 4 UUIDs are cryptographically random 122 bits of entropy. Guessing one is infeasible. But not all UUIDs are version 4. Version 1 UUIDs are time-based and incorporate the MAC address of the generating machine. They are partially predictable. An attacker who can observe UUID patterns in accessible resources can potentially narrow the UUID space for records they have not yet seen.

UUIDs with an IDOR elsewhere. Even if the primary resource uses random UUIDs, an IDOR on a related endpoint may expose the UUIDs of all records. An endpoint that lists documents may enforce authorization correctly. An endpoint that returns a document's metadata including its UUID for any authenticated user may not. The attacker enumerates document UUIDs through the leaky metadata endpoint and uses those UUIDs to access the documents through the IDOR.

User-enumerable identifiers. Some resources use identifiers that are knowable without iteration: usernames, email addresses, organization names, slug-based identifiers. A document at /api/documents/acme-corp/q4-strategy does not require numeric enumeration the identifier is semantically meaningful and potentially guessable.

The Real Attack: How An IDOR Becomes a Full Data Dump

The realistic exploitation of an IDOR in a multi-tenant SaaS application does not look like a manual one-at-a-time record retrieval. It looks like this.

Discovery. The attacker registers for a free trial or purchases a lower-tier plan. They receive access to the application. They examine the API requests their account generates during normal usage. They find that invoices are retrieved at /api/invoices/{id} where the ID is an integer. They have access to their own invoices IDs 10412 and 10413.

Confirmation. The attacker substitutes a different integer 10410. The API returns invoice 10410, which belongs to a different account. The IDOR is confirmed. One test. One confirmation.

Scope assessment. The attacker writes a short script. It iterates from ID 1 to 20000, sending a GET request for each invoice ID using their authentication token. It records every successful response. Within minutes, it has retrieved thousands of invoices belonging to hundreds of different companies.

Impact determination. The attacker reviews what the invoice data contains: company names, billing addresses, email addresses, contact names, purchase histories, plan types, revenue indicators. Depending on the application, the invoice data alone may be enough to identify competitors' customers, extract contact lists, or understand the pricing and usage patterns of the full customer base.

Escalation. The attacker notices that invoices contain references to other objects project IDs, user IDs, document IDs. They test whether those other endpoint types have the same IDOR. Many do, because IDOR tends to reflect a systemic authorization pattern rather than a single endpoint failure. The attacker now has access to projects, documents, user profiles, and communications the full data model of every customer on the platform.

The total time from account registration to access to the full customer dataset: less than an hour. The attacker's credential: a free trial account. The vulnerability: one missing authorization check in the invoice endpoint.

Why IDOR Is Systematically Underdetected

IDOR is the most consistently underdetected vulnerability class in API security assessments. The reasons are structural.

It requires two authenticated sessions. Finding IDOR requires verifying that user A can access data belonging to user B. A scanner that operates within a single authenticated session cannot verify this cross-account property. It can observe that the application returns data for a given identifier, but it cannot determine whether that data should be accessible to the requesting user without knowing who owns it. Traditional DAST tools, even with authenticated sessions, cannot perform cross-account comparison without the architecture to manage multiple simultaneous sessions.

It does not look like an attack in the logs. An authenticated user making sequential GET requests to /api/invoices/10410, /api/invoices/10411, /api/invoices/10412... looks like a user reading invoices. Each individual request is a legitimate-seeming authenticated API call. The attack pattern is in the sequence and the diversity of records returned, not in any individual request. Log analysis looking for anomalous request patterns can detect it at scale, but simple per-request anomaly detection will not.

It does not produce an error. A successful IDOR exploitation returns HTTP 200 with the requested data. There is no 403. There is no exception in the error log. The application worked correctly according to its own definition of correctness it received an authenticated request for an object ID and returned the object. The authorization check that should have detected the problem was never invoked, so it never fired.

It scales quietly. An attacker enumerating thousands of records does not need to make thousands of requests quickly. They can enumerate at a moderate rate that stays below any request-frequency anomaly threshold. A hundred requests per hour over a period of days looks like an engaged user with a large account.

The Authorization Pattern That Prevents It

The fix for IDOR is architecturally simple. The challenge is applying it consistently across every endpoint that retrieves, modifies, or deletes an object by identifier.

Query-level ownership enforcement. The most robust approach do not fetch the object by ID and then check ownership. Fetch the object by ID and ownership simultaneously:

Where tenant_id comes from the verified session token, not from the request parameters. This query returns no result if the requested invoice does not belong to the authenticated tenant. There is no separate authorization check to forget to add, no code path that returns the invoice before the check, no check that can be bypassed. The data never leaves the database if the ownership condition is not met.

Centralized authorization utilities. Ownership checks should be functions in the codebase, not patterns duplicated across endpoints. A reusable get_owned_invoice(invoice_id, current_user) function that encapsulates the ownership-scoped query is an authorization utility that is called identically everywhere it appears. Its absence in any code path is a gap that code review can detect. Its presence is an authorization audit trail.

Secondary identifier scoping. For applications that use UUIDs which do not have the sequential enumeration problem the authorization check is still necessary. UUIDs prevent enumeration but do not prevent a targeted attacker who has obtained a specific UUID through another means (introspection, related endpoint leakage, social engineering). The authorization check is the correct control; UUID randomness is a defense-in-depth measure, not a substitute.

Testing IDOR at Scale: The Two-Account Methodology

Finding IDOR and correctly assessing its scope requires a specific testing methodology that most automated tools do not implement.

Account A and Account B. The test begins with two authenticated accounts in the same application. Account A is the account whose data will be targeted. Account B is the account the attacker controls. During normal use of Account A, note the identifiers of objects it has access to invoice IDs, document IDs, project IDs, user IDs.

Cross-account access test. From Account B's authenticated session, request each of Account A's identifiers across every endpoint that accepts object identifiers. For each request: does Account B receive Account A's data? If yes, IDOR is confirmed on that endpoint.

Scope assessment. From Account B's session, iterate adjacent identifiers: the integers before and after Account A's known identifiers. Observe how many different tenant's data is returned across the iteration. This determines whether the IDOR is limited to predictable adjacent identifiers or spans the full dataset.

Cross-endpoint correlation. When IDOR is confirmed on one endpoint, test every other endpoint that accepts object identifiers of the same type. Authorization patterns that fail on one endpoint tend to fail on related endpoints the same developer built them, the same code pattern was reused, the same authorization oversight was made.

Automated enumeration scoping. For the purpose of demonstrating the full impact of the finding, iterate through a representative range of identifiers from Account B's session and document what fraction of responses contain data from other tenants. This converts "we found an IDOR" into "this IDOR exposes N records belonging to M tenants" the information that communicates actual business impact rather than abstract vulnerability severity.

The Business Case for Treating IDOR as Critical Priority

In vulnerability management frameworks, individual IDOR findings are sometimes scored as high severity rather than critical, particularly when they affect only one record type or require authentication. This scoring can lead engineering teams to deprioritize IDOR remediation in favor of higher-scored vulnerabilities.

The scoring misses the scale dimension.

A SQL injection vulnerability that allows unauthenticated database access is clearly critical. A single IDOR vulnerability in a multi-tenant SaaS application may produce identical real-world impact full access to every customer's data while scoring lower because each individual record exposure requires an authenticated session and a specific identifier.

The correct framing is not "this vulnerability exposes one record" but "this vulnerability exposes every record in the system to any authenticated user." That reframing changes the remediation priority and the urgency calculation significantly.

For a SaaS company, the specific business consequences of IDOR exploitation at scale:

Regulatory. A breach that exposes personal data of EU residents triggers GDPR notification requirements. An IDOR that exposes customer data at scale is a reportable breach in most jurisdictions with data protection frameworks. The regulatory exposure is determined by the total number of records accessible, not by how many the attacker actually retrieved.

Contractual. Enterprise SaaS contracts typically contain data security representations. An IDOR vulnerability in a multi-tenant platform is a breach of those representations the data isolation guarantee the customer was promised was not in place. Disclosure of this to enterprise customers triggers escalation processes that can result in contract termination.

Competitive. Customer data that is exposed via IDOR frequently includes information that is competitively sensitive: usage patterns, revenue indicators, customer lists, pricing information. A competitor who discovers and exploits an IDOR before the vendor does has acquired information they should not have.

The individual IDOR finding is a technical issue. The scale implication is a business issue.

Closing: The Reference Wasn't Insecure. The Authorization Was Absent.

"Insecure Direct Object Reference" is the established name. The more precise description is "absent authorization on a direct object reference" because the reference itself is not the problem. References to objects are necessary and appropriate. The problem is that the reference was used without verifying whether the requesting user was entitled to what it referenced.

Every API that handles multi-tenant data has direct object references. That is not the issue. The issue is the fraction of those references that enforce authorization that check whether the object identified by the reference belongs to the entity making the request before returning or modifying the referenced object.

In a well-implemented API, that fraction is one hundred percent. Every endpoint that accepts an object identifier verifies ownership before proceeding. The query includes the ownership condition. The code path cannot return data that does not belong to the requesting tenant, because the database never returns it.

In an imperfectly implemented API which describes the majority of production SaaS applications at any given point in time some fraction of object references are missing their authorization check. Each missing check is one open door into the full customer dataset of the platform.

One door is enough. One door, at scale, is the breach.

Axeploit finds IDOR by operating as real authenticated users across real application workflows creating multiple accounts, identifying objects accessible to each, and systematically testing whether those objects are accessible across accounts. Its cross-account testing methodology confirms IDOR findings with evidence the specific data returned from the wrong account's perspective and assesses scope by iterating adjacent identifiers to determine whether the finding is isolated or platform-wide. A confirmed IDOR finding from Axeploit includes the enumerated scope, the affected endpoint set, and the tenant isolation assessment that converts a technical finding into a business impact statement.

Integrate Axeploit into your workflow today!