Skip to main content
Offensive360
Home / Knowledge Base / Broken Access Control / IDOR
Critical CWE-639 A01:2021 Broken Access Control

Broken Access Control / IDOR

Broken access control and Insecure Direct Object Reference (IDOR) flaws let attackers access or modify resources they don't own. Learn detection patterns and secure authorization practices.

Affects: C#JavaJavaScriptPHPPythonRubyGo

What is Broken Access Control / IDOR?

Broken Access Control is the #1 vulnerability in the OWASP Top 10, representing failures in enforcing restrictions on what authenticated users are allowed to do. Insecure Direct Object Reference (IDOR) is a specific and extremely common subtype: the application exposes internal object identifiers (database IDs, filenames, UUIDs) and allows users to access any record simply by changing that identifier.

A classic example: a user views their invoice at /api/invoices/1042. By changing 1042 to 1041, they retrieve another user’s invoice — because the server never checks whether the requester owns that record.

Beyond IDOR, broken access control includes vertical privilege escalation (a regular user accessing admin-only functionality), path traversal, and missing function-level access controls on API endpoints.

How exploitation works

# Victim's request
GET /api/orders/99201 HTTP/1.1
Authorization: Bearer <victim_token>
→ Returns victim's order

# Attacker increments the ID
GET /api/orders/99200 HTTP/1.1
Authorization: Bearer <attacker_token>
→ Returns ANOTHER user's order — no ownership check performed

Automated IDOR discovery tools enumerate IDs in bulk, extracting thousands of records in minutes if no rate limiting or ownership enforcement is in place.

Vulnerable code examples

C# / ASP.NET Core

// VULNERABLE: No ownership check — any authenticated user can fetch any order
[HttpGet("orders/{id}")]
[Authorize]
public async Task<IActionResult> GetOrder(int id)
{
    var order = await _db.Orders.FindAsync(id);
    return Ok(order); // Missing: verify order.UserId == currentUserId
}

Java / Spring

// VULNERABLE: Admin endpoint accessible to any authenticated user
@GetMapping("/api/admin/users/{id}")
@PreAuthorize("isAuthenticated()") // Should be hasRole('ADMIN')
public ResponseEntity<User> getUser(@PathVariable Long id) {
    return ResponseEntity.ok(userRepository.findById(id).orElseThrow());
}

Secure code examples

C# / ASP.NET Core — ownership enforcement

// SECURE: Explicitly verify the caller owns the requested resource
[HttpGet("orders/{id}")]
[Authorize]
public async Task<IActionResult> GetOrder(int id)
{
    var currentUserId = User.GetUserId();
    var order = await _db.Orders
        .FirstOrDefaultAsync(o => o.Id == id && o.UserId == currentUserId);

    if (order == null) return NotFound(); // Returns 404, not 403, to avoid enumeration
    return Ok(order);
}

Python / Django — query scoped to current user

# SECURE: Filter queryset by the authenticated user — can never access others' data
@login_required
def get_document(request, doc_id):
    doc = get_object_or_404(Document, id=doc_id, owner=request.user)
    return JsonResponse(doc.to_dict())

What Offensive360 detects

  • Unguarded object lookups — Database queries using user-supplied IDs without an ownership or role condition
  • Missing role checks — Endpoints decorated with generic [Authorize] / isAuthenticated() that should require specific roles or permissions
  • Direct file access — File download/read operations using user-supplied filenames or paths without access verification
  • Insecure admin routes — Administrative endpoints with insufficient authorization annotations
  • UUID-only security — Objects “protected” only by UUID obscurity, with no actual permission check

Remediation guidance

  1. Enforce ownership at the data layer — Every query that retrieves user-specific data must include the authenticated user’s ID as a filter condition.

  2. Apply role-based authorization to all endpoints — Do not rely on hidden UI elements to restrict access; verify authorization in the server-side handler.

  3. Use indirect references — Map internal IDs to session-scoped tokens (e.g., a UUID that is only valid within the current session) to make enumeration harder.

  4. Deny by default — Access control should default to deny. Explicitly grant permissions rather than implicitly allowing access.

  5. Log and alert on access violations — Detect enumeration attacks by monitoring for high-frequency 403/404 responses on resource endpoints.

References

By Offensive360 Security Research Reviewed: March 2026

Detect Broken Access Control / IDOR automatically

Run Offensive360 SAST on your codebase to find this and 100+ other vulnerabilities.