Overview
Broken Object Level Authorization (BOLA) vulnerabilities occur when an application trusts user-provided identifiers to access resources without validating ownership or access rights. CVE-2017-0249 describes an elevation of privilege in ASP.NET Core caused by improper sanitization of web requests, which could enable bypassing authorization and gaining access to restricted resources.
In real ASP.NET Core apps, this manifests when an API endpoint trusts a client-supplied object ID to fetch or mutate a resource without verifying that the current user owns or is allowed to operate on that resource. An attacker can enumerate or craft requests to operate on other users' data, effectively elevating privileges within the application.
Remediation involves enforcing server-side authorization for each resource: verify ownership or permissions before performing actions, prefer claims-based or policy-based authorization, and guard against relying on route data alone. The fix is to perform an explicit ownership check or policy-based authorization in code, and to test with scenarios derived from CVE-2017-0249.
Code Fix Example
ASP.NET Core API Security Remediation
// Vulnerable pattern (no ownership check)
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Demo
{
public class Document { public int Id { get; set; } public string OwnerId { get; set; } public string Content { get; set; } }
public class AppDbContext : DbContext { public DbSet<Document> Documents { get; set; } public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } }
[ApiController]
[Route("[controller]")]
public class DocumentsV1Controller : ControllerBase
{
private readonly AppDbContext _db;
public DocumentsV1Controller(AppDbContext db) { _db = db; }
[HttpGet("documents/{id}")]
public IActionResult GetDocument(int id)
{
// Vulnerable: returns any document by id without ownership check
var doc = _db.Documents.Find(id);
if (doc == null) return NotFound();
return Ok(doc);
}
// Fixed pattern: separate secure endpoint to demonstrate side-by-side
[HttpGet("documents-secure/{id}")]
public async Task<IActionResult> GetDocumentSecure(int id)
{
var doc = await _db.Documents.FindAsync(id);
if (doc == null) return NotFound();
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
if (doc.OwnerId != userId) return Forbid();
return Ok(doc);
}
}
}
// Note: In a real app, prefer a single endpoint using a policy or resource-based authorization.