đŸ›Ąïž Application Security CheatSheet

Authorization Deep Dive (IDOR / BOLA / BFLA)

Authentication answers: “Who are you?”
Authorization answers: “Are you allowed to do this to this data?”

In real incidents: IDORs happen when teams trust UI flows. The server needs to re-check ownership every time, even if it feels repetitive.

Key idea: AuthZ is not “a feature”. It’s a rule enforced on every request that touches data.

Why authorization bugs happen (deep reason)

Mental model: “who → what → which object → policy decision”

Every sensitive request must enforce:

IDOR / BOLA (Broken Object Level Authorization)

What it is

When the server uses an object identifier from the request (path/query/body) but does not verify the caller is allowed to access that object.

Vulnerable pattern (example)

// Node/Express (example)
app.get("/api/orders/:id", async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  // ❌ Missing ownership check
  res.json(order);
});

Secure pattern

// ✅ Enforce ownership in the query (best)
app.get("/api/orders/:id", async (req, res) => {
  const order = await db.orders.findOne({ id: req.params.id, ownerId: req.user.id });
  if (!order) return res.status(404).json({ error: "Not found" });
  res.json(order);
});
Why query-level enforcement is better: you avoid “fetch then check” mistakes and reduce accidental data exposure.

Testing methodology (systematic)

Fix recommendations (experienced answer)

BFLA (Broken Function Level Authorization)

What it is

Calling privileged actions (approve, export, admin changes) without role enforcement.

Vulnerable pattern

// ❌ Any authenticated user can approve refunds
app.post("/api/refunds/:id/approve", async (req, res) => {
  await refunds.approve(req.params.id);
  res.json({ ok: true });
});

Secure pattern

// ✅ Explicit policy check
app.post("/api/refunds/:id/approve", requireRole("finance_admin"), async (req, res) => {
  await refunds.approve(req.params.id);
  res.json({ ok: true });
});

Testing methodology

Fix

Preventing regressions

Interview-ready answers (60-second + 2-minute)

60-second answer

Authorization is the server deciding who can do what to which resource. Bugs happen when APIs trust user-provided identifiers (IDOR/BOLA) or forget role checks on privileged actions (BFLA). The fix is consistent policy enforcement: query-level ownership checks, centralized authorization middleware/policies, deny-by-default, and regression tests for the role×endpoint matrix.

2-minute answer

I think of AuthZ as a policy decision applied to every request that touches data. The common failure mode is “UI rules” (hidden buttons) being mistaken for server rules. For object-level authorization, I enforce access at the data layer (e.g., WHERE id=? AND ownerId=?) so there’s no “fetch-then-check” mistake. For function-level authorization, I gate privileged routes (approve/export/admin actions) with explicit policy checks. I also cover tricky cases like nested resources (org→project→invoice), indirect references (shared links), multi-tenant scoping, and bulk endpoints. Finally I prevent regressions with automated tests for forbidden actions (403), policy centralization, and code review rules.

How authorization exploitation progresses (attacker mindset)

This is a real-world process explanation (no copy/paste exploit steps). Attackers don’t start with “dump data” — they start by proving inconsistent policy enforcement.

Phase 1: Inventory & classify endpoints

Phase 2: Prove policy inconsistency

Phase 3: Expand scope via relationships

Phase 4: Look for high-impact actions

Interview takeaway: attackers escalate from “wrong object” → “wrong tenant” → “privileged action” by following relationships and inconsistent checks.

Tricky edge cases & bypass patterns (what attackers look for)

Safe validation workflow (defensive verification)

Goal: prove authorization failure with minimal exposure and no unnecessary data access.
  1. Baseline: capture the request for a resource owned by User A (or Role Admin).
  2. Cross-identity test: repeat as User B (or lower role) using the same resource ID.
  3. Confirm scope: verify not only response codes, but side effects (status changes, notifications, audit logs).
  4. Relationship checks: repeat for nested resources (org → project → invoice) and indirect assets (attachments/exports).
  5. Regression test idea: add an automated test asserting forbidden access returns 403.

Defensive patterns & fixes (Node.js)

Pattern 1: Query-level enforcement (best for BOLA)

// ✅ Ownership enforced in the query
app.get("/api/orders/:id", async (req, res) => {
  const order = await db.orders.findOne({ id: req.params.id, ownerId: req.user.id });
  if (!order) return res.status(404).json({ error: "Not found" });
  res.json(order);
});

Pattern 2: Central policy middleware (best for BFLA)

// ✅ Explicit policy check for privileged actions
function requireRole(role) {
  return (req, res, next) => {
    if (!req.user || req.user.role !== role) return res.status(403).json({ error: "Forbidden" });
    next();
  };
}

app.post("/api/refunds/:id/approve", requireRole("finance_admin"), async (req, res) => {
  await refunds.approve(req.params.id);
  res.json({ ok: true });
});
experienced tip: prefer deny-by-default. Make “who can do what” visible and testable in one place.

Confidence levels (how sure are you?)

Checklist (quick review)

Remediation playbook

  1. Contain: disable/guard the vulnerable endpoint or feature flag it.
  2. Fix: implement centralized policy checks + query-level ownership filters.
  3. Scope: search codebase for similar endpoints (same resource type, same pattern).
  4. Test: add regression tests for forbidden cases (403).
  5. Monitor: alert on unusual access patterns and privileged action usage.
  6. Review: enforce code review policy: “show the authorization decision” for every endpoint.

Interview Questions & Answers (Easy → Hard)

Easy

  1. AuthN vs AuthZ?
    A: AuthN is “who are you”; AuthZ is “are you allowed to do this to this resource?”.
  2. What is IDOR/BOLA?
    A: When the server uses an object ID from the request but doesn’t verify the caller is allowed to access that object.
  3. Why is “hiding a button” not a fix?
    A: UI is not enforcement. Attackers call APIs directly; the server must enforce policy.
  4. Best primary fix for BOLA?
    A: Ownership enforcement at the query/data layer (scope by ownerId/tenantId).
  5. Best primary fix for BFLA?
    A: Central policy checks/middleware with deny-by-default.
  6. What HTTP code for forbidden?
    A: 403 for authenticated but not allowed; 401 when not authenticated.

Medium

  1. How do you test for BOLA safely?
    A: Two identities. Create object as A, replay as B with the same ID, confirm response + side effects.
  2. Where do these bugs hide most?
    A: Nested resources, bulk endpoints, exports, attachments, and admin tooling.
  3. Why is “fetch then check” risky?
    A: Easy to forget checks; may leak fields before check. Query-level enforcement reduces exposure.
  4. How do you handle multi-tenant scope?
    A: Every query must include tenant boundary (orgId/tenantId) in addition to ownership/role.
  5. Follow-up: what’s your prevention strategy?
    A: Centralize authZ, add role×endpoint tests, and require visible policy checks in code review.
  6. Follow-up: why not rely on frontend checks?
    A: Frontend is bypassable. Server must enforce.

Hard

  1. Scenario: nested route checks child but not parent. Risk?
    A: Parent scoping bypass (org/project boundary). Fix by validating both parent and child belong to caller/tenant.
  2. Scenario: export endpoint leaks fields not present in UI. Why common?
    A: Export paths are often built quickly and skip field-level policy checks. Fix: field allow-lists and policy per export.
  3. Scenario: batch update accepts list of IDs. What’s the pitfall?
    A: Partial authorization—some IDs may be unauthorized. Fix: authorize each ID or constrain query to authorized set only.
  4. Scenario: support role can “view” but not “export”. How enforce?
    A: Separate actions in policy (view vs export), enforce deny-by-default, audit exports.
  5. Follow-up: what tests do you add after fixing?
    A: Integration tests asserting forbidden access is 403 across role×endpoint×resource combinations.
  6. Follow-up: how do you keep policy consistent at scale?
    A: Central policy engine, code scanning for raw routes without checks, and shared data-access helpers.
Safety note: for understanding +