IDOR: The Missing Check
Insecure Direct Object Reference — when the server trusts the client-supplied identifier without verifying ownership. Change one number, see someone else data.
Insecure Direct Object Reference — when the server trusts the client-supplied identifier without verifying ownership. Change one number, see someone else data.
Insecure Direct Object Reference (IDOR) is a type of access control vulnerability that occurs when an application exposes a direct reference to an internal object — such as a database record, file, or resource — and fails to verify that the user is authorised to access it. The result is that any authenticated user can access data belonging to other users simply by changing a parameter value.
Imagine a web application that displays user profiles using URLs like /profile?user_id=5. If the server fetches the profile by that ID without checking who made the request, an attacker can change the number to user_id=6 and see another user's personal data — name, email, phone number, and more.
IDOR is not limited to numeric IDs. It applies to any direct object reference that a user can manipulate: UUIDs in API paths, email addresses in POST bodies, filenames in download endpoints, and invoice codes in billing portals. The vulnerability is not that the reference is predictable — even UUIDs are vulnerable if the server trusts the client to specify which resource to return. The bug is the absence of a server-side ownership check.
The sandbox below simulates a company intranet HR portal. You are logged in as employee #3. Try navigating between employee profiles by typing different IDs into the URL bar or using the arrow buttons. With the auth check disabled, you can read anyone's salary and contact details. Enable the auth check to see what a properly secured endpoint looks like.
In 2018, a security researcher discovered an IDOR vulnerability in Facebook's “View As” feature — a tool that lets users preview how their profile looks to a specific friend. The feature accepted a friend ID parameter, but the server did not verify that the requested profile belonged to the current user. By manipulating the ID, an attacker could view any Facebook profile's non-public data, including phone numbers, email addresses, and private photos.
Facebook patched the issue after a bug bounty report, but the incident illustrates the core IDOR pattern — a user-supplied identifier used without an ownership check. IDOR vulnerabilities remain one of the most common access control flaws reported in bug bounty programs today, and they frequently appear in financial systems, healthcare portals, and SaaS platforms.
The defense against IDOR is to never trust user-supplied identifiers without verifying that the authenticated user owns the requested resource. The session contains the user's identity; every database query that retrieves a user-specific object should include that identity in the WHERE clause.
// VULNERABLE - trusts the user-supplied ID
app.get('/api/profile/:id', async (req, res) => {
const profile = await db.query(
'SELECT * FROM profiles WHERE id = $1',
[req.params.id],
);
res.json(profile.rows[0]);
});
// SAFE - verifies ownership against session
app.get('/api/profile/:id', async (req, res) => {
const profile = await db.query(
'SELECT * FROM profiles WHERE id = $1 AND user_id = $2',
[req.params.id, req.session.userId],
);
if (!profile.rows[0]) return res.status(403).json({ error: 'Access denied' });
res.json(profile.rows[0]);
});Additional layers: use session-derived identifiers where possible (never ask the client for the current user's ID), avoid exposing database primary keys in URLs by using opaque identifiers or slugs, and enforce access control in a reusable middleware layer rather than in individual route handlers.
?user_id=5 to ?user_id=6 — is enough to expose another user's data.1.What makes a web endpoint vulnerable to IDOR?
2.Does switching from numeric IDs to UUIDs fix IDOR?
3.A developer writes: const profile = await db.query("SELECT * FROM profiles WHERE id = $1", [req.params.id]). What is the verdict?