What is IDOR (Insecure Direct Object Reference)?
IDOR happens when a user can access data by changing an identifier (like ?userId=42
) without authorization checks. In React, it often appears as “trusting the client” and exposing raw IDs.
👉 More security write-ups: Pentest Testing Blog
A quick vulnerable example (don’t ship this)
// Profile.jsx (vulnerable)
useEffect(() => {
fetch(`/api/users/${params.userId}`)
.then(r => r.json())
.then(setProfile);
}, [params.userId]);
If an attacker changes the URL to /users/12345
, they might see another user’s data if the server doesn’t enforce ownership.
Screenshot of our free Website Vulnerability Scanner tool page
Screenshot of the free tools webpage where you can access security assessment tools.
Fix 1: Always authorize on the server
// Express route (secure)
app.get('/api/users/:id', auth(), async (req, res) => {
const { id } = req.params;
if (req.user.id !== id && !req.user.roles.includes('admin')) {
return res.status(403).json({ error: 'Forbidden' });
}
const user = await db.user.findById(id);
res.json(user);
});
Rule: React may request, but the server decides.
Fix 2: Scope queries to the logged-in user
// Prefer "me" endpoints that cannot be IDORed
app.get('/api/me/profile', auth(), async (req, res) => {
const user = await db.user.findById(req.user.id);
res.json(user);
});
In React:
useEffect(() => {
fetch('/api/me/profile', { credentials: 'include' })
.then(r => r.json())
.then(setProfile);
}, []);
Sample assessment report from our tool to check Website Vulnerability
Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities.
Fix 3: Don’t trust client-side checks
// This is NOT security; it’s UX only
if (!currentUser.isAdmin) return null; // still fetches if called elsewhere
Enforce authorization on the backend and hide UI in React for a clean UX.
Fix 4: Secure GraphQL resolvers
// GraphQL resolver (secure)
const resolvers = {
Query: {
order: async (_, { id }, ctx) => {
const order = await db.order.findById(id);
if (order.userId !== ctx.user.id && !ctx.user.isAdmin) {
throw new Error('Forbidden');
}
return order;
}
}
};
Fix 5: Use opaque IDs, but still check auth
// Even with UUIDs or hashes, you must check ownership
app.get('/api/docs/:docId', auth(), async (req, res) => {
const doc = await db.doc.findById(req.params.docId);
if (doc.ownerId !== req.user.id) return res.sendStatus(403);
res.json(doc);
});
How to test for IDOR (safe steps)
- Log in as a normal user.
- Change IDs in URLs or request bodies (
/api/orders/1001 → 1002
). - Watch the response—any data you don’t own? Report/fix immediately.
- Automate checks: run our free scanner and then retest fixes.
👉 Try it free: free.pentesttesting.com
Services to help you go faster
Managed IT Services
Harden infra, monitor, and patch continuously.
➡️ https://www.pentesttesting.com/managed-it-services/
AI Application Cybersecurity
Threat modeling for ML features, model/API hardening.
➡️ https://www.pentesttesting.com/ai-application-cybersecurity/
Offer Cybersecurity to Your Clients
White-label pentesting & remediation you can resell.
➡️ https://www.pentesttesting.com/offer-cybersecurity-service-to-your-client/
Stay updated
Subscribe on LinkedIn https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7327563980778995713
Pro tip: Block IDORs with server-side authorization, least-privilege data access, and “me-scoped” endpoints. Then validate with a scan and regression tests.
Top comments (0)