IDOR Explained: Insecure Direct Object References
Learn about Insecure Direct Object Reference vulnerabilities where attackers access unauthorized data by manipulating object identifiers in requests.
When Any User Can Access Any Account
You change a number in the URL: /user/profile/123 to /user/profile/124. The page loads another user's name, email, and billing details. No password prompt, no error — just someone else's private data. This is Insecure Direct Object Reference (IDOR): the app exposes internal object references (user IDs, invoice numbers, file paths) without checking whether the current user is authorized to access them.
Prerequisites
Before studying IDOR, you should understand:
How IDOR Works
Applications use identifiers to reference objects:
Basic Example
// Vulnerable — no authorization check
app.get('/api/invoices/:id', (req, res) => {
const invoice = db.invoices.findById(req.params.id);
res.json(invoice);
});
The attacker simply changes the ID:
GET /api/invoices/1001 -> User's own invoice
GET /api/invoices/1002 -> Another user's invoice (IDOR!)
Types of IDOR
Horizontal IDOR
Accessing resources at the same privilege level but belonging to another user — viewing another user's private messages.
Vertical IDOR (Privilege Escalation)
Accessing resources requiring higher privileges — a regular user accessing an admin endpoint.
File-Based IDOR
GET /download?file=user_1234_report.pdf
GET /download?file=user_5678_report.pdf
Finding IDOR Vulnerabilities
Manual Testing Workflow
IDOR Prevention
Implement Authorization Checks
app.get('/api/invoices/:id', authenticate, (req, res) => {
const invoice = db.invoices.findById(req.params.id);
if (!invoice) return res.status(404).send('Not found');
if (invoice.userId !== req.user.id) {
return res.status(403).send('Forbidden');
}
res.json(invoice);
});
Use Indirect References
app.get('/my/invoices/:ref', authenticate, (req, res) => {
const invoiceId = sessionInvoiceMap[req.session.id][req.params.ref];
if (!invoiceId) return res.status(404).send('Not found');
const invoice = db.invoices.findById(invoiceId);
res.json(invoice);
});
Use Unpredictable Identifiers
CREATE TABLE invoices (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id INTEGER REFERENCES users(id)
);
Note: Unpredictable IDs are obfuscation, not security. Always pair with authorization.
Real-World Examples
Telegram IDOR (2020): A researcher discovered Telegram's "People Nearby" feature exposed precise user locations through an IDOR vulnerability.
Facebook IDOR (2019): Security researchers found an IDOR vulnerability allowing viewing private photos from any Facebook album.
Uber Bug Bounty (2015): Multiple IDORs in Uber's partner dashboard allowed accessing driver earnings, trip histories, and personal information.
Common Mistakes
Assuming UUIDs are secure: Unpredictable IDs are not authorization — endpoints still need permission checks.
Client-side checks only: Frontend authorization is easily bypassed. All checks must be server-side.
Inconsistent authorization patterns: Some endpoints check authorization while others do not.
Best Practices
Related Tools
Related Articles
Summary
IDOR vulnerabilities arise from missing authorization checks on object references. The fix is straightforward: verify the requesting user has permission to access the specific resource on every request. Use indirect references and centralized access control patterns to reduce risk.