Insecure Direct Object Reference (IDOR)
What Is This Vulnerability?
IDOR vulnerabilities occur when an application exposes internal object identifiers (like database IDs) in URLs or request parameters and does not verify that the authenticated user has permission to access the referenced object. Attackers simply change the ID in the request to access or modify other users' data.
Why It Happens
Applications often use sequential numeric IDs or predictable identifiers in API endpoints (e.g., /api/orders/123). When the backend retrieves the record by ID without checking whether the requesting user owns that record, any authenticated user can access any other user's data by guessing or iterating through IDs.
Example Code
app.get("/api/orders/:id", requireAuth, async (req, res) => {
const order = await db.query(
"SELECT * FROM orders WHERE id = $1",
[req.params.id]
);
if (!order.rows[0]) return res.status(404).json({ error: "Not found" });
res.json(order.rows[0]);
});app.get("/api/orders/:id", requireAuth, async (req, res) => {
const order = await db.query(
"SELECT * FROM orders WHERE id = $1 AND user_id = $2",
[req.params.id, req.user.id]
);
if (!order.rows[0]) return res.status(404).json({ error: "Not found" });
res.json(order.rows[0]);
});How Hackers Exploit It
Attackers authenticate with their own account and observe the ID pattern in API responses. They then script requests with incrementing or decrementing IDs to enumerate all records. Tools like Burp Suite's Intruder automate this process. The attacker can download all orders, invoices, messages, or personal data belonging to other users in minutes.
How to Fix It
Always include the authenticated user's ID in database queries as a filter condition. Use UUIDs instead of sequential integers to make IDs harder to guess (but do not rely on this alone). Implement row-level security policies in your database. Create a shared authorization layer or middleware that checks ownership before returning any record.