Broken Access Control: Preventing IDOR Vulnerabilities
Broken access control means a user can do something they shouldn't be allowed to. The most common form is IDOR (insecure direct object reference): change an ID in a request and see someone else's data.
The vulnerable pattern
// GET /api/invoices/1043
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
const invoice = await db.invoices.findById(req.params.id);
res.json(invoice); // any logged-in user can read ANY invoice
});
Being logged in (authentication) says who you are. It says nothing about which invoices you may see (authorisation).
Fix 1: scope the query to the user
app.get('/api/invoices/:id', requireLogin, async (req, res) => {
const invoice = await db.invoices.findOne({
id: req.params.id,
accountId: req.user.accountId, // the ownership check is part of the query
});
if (!invoice) return res.status(404).json({ error: 'Not found' }); // don't reveal it exists
res.json(invoice);
});
Fix 2: central policy checks
const can = {
viewInvoice: (user, invoice) => invoice.accountId === user.accountId,
refundInvoice: (user, invoice) => can.viewInvoice(user, invoice) && user.role === 'admin',
};
if (!can.refundInvoice(req.user, invoice)) throw new HttpError(403, 'Forbidden');
Keeping rules in one place makes them easier to review and test than checks scattered through handlers.
Other forms of broken access control
- Admin endpoints protected only by hiding the button in the UI.
- Mass assignment:
PATCH /users/mewith{"role": "admin"}in the body. Allow-list updatable fields. - Missing checks on bulk or export endpoints.
- Trusting a
userIdsent by the client instead of the one in the session.
Testing
- Write automated tests with two users: user B must get 404/403 for user A's resources on every endpoint.
- Use unguessable IDs (UUIDs) as defence in depth, but never as the only protection.
- Review new endpoints with one question: "where is the authorisation check?"
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.