What is an IDOR vulnerability?
Insecure Direct Object Reference. A vulnerability where an application exposes internal object references (like database IDs) that attackers can manipulate to access unauthorized data.
Understanding IDOR
IDOR occurs when applications use user-controllable input to directly access objects (database records, files, etc.) without proper authorization checks. It's one of the most common vulnerabilities found in web applications and can lead to massive data breaches. The fix is simple - always check if the user is authorized to access the resource - but it's frequently forgotten.
Examples
- Changing /api/invoices/123 to /api/invoices/124 to view another user's invoice
- Modifying a user_id parameter in a request to access another account
- Incrementing file IDs to download other users' uploads
- Manipulating order IDs to view or cancel other customers' orders
How to Prevent
- Always verify the authenticated user has permission to access the requested resource
- Use UUIDs or other non-guessable identifiers instead of sequential IDs
- Implement object-level authorization checks on every endpoint
- Add the user constraint to database queries (WHERE user_id = ?)
- Log and monitor access patterns for enumeration attempts
- Use automated testing tools to detect IDOR vulnerabilities
- Consider using indirect reference maps for sensitive resources
Code Examples
Vulnerable API Endpoint
The vulnerable code fetches any invoice by ID without checking ownership. The secure version ensures the requesting user owns the invoice.
// VULNERABLE: No authorization check
app.get('/api/invoices/:id', async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
res.json(invoice);
});
// Any authenticated user can access ANY invoice by changing the ID
// GET /api/invoices/123 → GET /api/invoices/456 // SECURE: Verify ownership before returning data
app.get('/api/invoices/:id', async (req, res) => {
const invoice = await Invoice.findById(req.params.id);
// Check if the invoice belongs to the authenticated user
if (invoice.userId !== req.user.id) {
return res.status(403).json({ error: 'Forbidden' });
}
res.json(invoice);
});
// Even better: Query with user constraint
app.get('/api/invoices/:id', async (req, res) => {
const invoice = await Invoice.findOne({
_id: req.params.id,
userId: req.user.id // Only find if owned by user
});
if (!invoice) {
return res.status(404).json({ error: 'Not found' });
}
res.json(invoice);
}); File Download IDOR
// VULNERABLE: Predictable file paths
app.get('/download/:fileId', (req, res) => {
const filePath = `/uploads/${req.params.fileId}.pdf`;
res.download(filePath);
});
// Attacker can enumerate: /download/1, /download/2, etc. // SECURE: Use UUIDs and verify ownership
app.get('/download/:fileId', async (req, res) => {
const file = await File.findOne({
uuid: req.params.fileId, // UUID instead of sequential ID
ownerId: req.user.id // Must belong to user
});
if (!file) {
return res.status(404).json({ error: 'File not found' });
}
res.download(file.path);
}); Real-World Incidents
Facebook (Meta)
2019IDOR vulnerability allowed attackers to view private friend lists of any Facebook user by manipulating GraphQL queries.
Impact: Private data of millions of users potentially exposed
Uber
2019IDOR in driver document upload allowed accessing other drivers' documents by changing the driver ID parameter.
Impact: Personal documents (licenses, insurance) of drivers exposed
US Department of Defense
2020Bug bounty hunter found IDOR allowing access to any service member's PII by manipulating a record ID.
Impact: $4,000 bounty paid, vulnerability patched
Worried about IDOR in your app?
Our security audits identify vulnerabilities like this before attackers do. Get expert manual review of your codebase.