Broken Access Control: Preventing IDOR Vulnerabilities

A
Author
07 Sep, 2026 1 min read 1.24K views

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/me with {"role": "admin"} in the body. Allow-list updatable fields.
  • Missing checks on bulk or export endpoints.
  • Trusting a userId sent 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.

Leave a comment

Comments are reviewed before they appear.