Cybreach Consulting Prendre RDV
Back to articles
Vulnerabilities

Broken access control: IDOR, privilege escalation and authorisation bypass

Access control is the mechanism that ensures an authenticated user can only access the resources and actions they're authorised for. It's the number one category in the OWASP Top 10 since 2021. Unlike authentication (which verifies identity), authorisation verifies rights. These two controls are distinct and must be implemented independently.

Insecure direct object reference (IDOR)

An IDOR occurs when a predictable identifier (numeric ID, filename, UUID) allows access to a resource without verifying the requesting user actually owns it. It's the most frequent access control flaw in audits. It often appears in REST APIs.

IDOR example and fix

// Vulnérable : accès à n'importe quelle facture par ID
GET /api/invoices/1337

// Serveur renvoie la facture sans vérifier à qui elle appartient :
return db.query('SELECT * FROM invoices WHERE id = ?', [req.params.id]);

// Corrigé : vérification de la propriété
return db.query(
  'SELECT * FROM invoices WHERE id = ? AND user_id = ?',
  [req.params.id, req.session.userId]
);

Using UUIDs instead of sequential numeric IDs reduces discovery by enumeration but doesn't replace access control. An attacker who knows a UUID (through a leak, sharing, or interception) can still access it if the control is absent.

Privilege escalation

Privilege escalation allows a user to gain rights above those assigned to them. Horizontal escalation means accessing another user's resources at the same level (IDOR). Vertical escalation means gaining rights of a higher role (user → administrator).

Vertical escalation typically occurs when role checks rely on client-side data (URL parameter, hidden form field, modifiable JWT value) or when admin endpoints don't systematically check the caller's role.

Server-side role check (Express.js middleware)

function requireRole(role) {
  return (req, res, next) => {
    if (!req.session.user || req.session.user.role !== role) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

// Appliqué sur toutes les routes admin :
app.use('/admin', requireRole('admin'));

Business logic bypass

Business logic flaws exploit sequences of actions not anticipated by developers. Examples: modifying an item's price directly in the request before cart validation, skipping to the payment step without completing previous steps, reusing an already-used promo code by manipulating session state, applying a discount intended for a specific profile by modifying a parameter.

These flaws can't be detected by automated scanners because they're specific to each application's logic. They require manual review and functional security testing.

CORS misconfiguration

CORS (Cross-Origin Resource Sharing) is the mechanism that lets a script from one domain make requests to another domain. A misconfiguration can allow a malicious site to call your API while impersonating an authenticated user via their cookies.

Dangerous vs. secure CORS configuration

// Dangereux : reflète l'origine de la requête sans validation
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');

// Sécurisé : liste blanche d'origines autorisées
const ALLOWED_ORIGINS = ['https://app.example.com', 'https://admin.example.com'];
const origin = req.headers.origin;
if (ALLOWED_ORIGINS.includes(origin)) {
  res.setHeader('Access-Control-Allow-Origin', origin);
  res.setHeader('Access-Control-Allow-Credentials', 'true');
}

User account enumeration

Account enumeration allows an attacker to confirm which identifiers (emails, usernames) exist in the system. This occurs when error messages differ depending on whether the identifier exists: "Incorrect password" (identifier exists) vs. "Account not found" (identifier doesn't exist). The attacker can then target only confirmed accounts.

The fix: use a generic identical message regardless of the failure reason ("Incorrect email or password"), and ensure response time is constant (a hash must be computed even if the identifier doesn't exist, to prevent timing attacks).

Summary

  1. Check ownership on every access: for each resource returned, filter by current user ID server-side
  2. Server-side role checks: never based on data sent by the client
  3. Test business logic: verify step sequences, prices, quantities, promo codes
  4. CORS: explicit whitelist: never reflect the Origin header without validation
  5. Generic error messages: same message for unknown identifier and incorrect password

A question after reading?

Suspecting flaws in your access controls? Send a message.

Or book a 30-minute scoping call directly

Book a call