Broken Object Property Level Authorization

Broken Object Property Level Authorization in ASP.NET Core [CVE-2017-0249]

[Updated month year] Updated CVE-2017-0249

Overview

Broken Object Property Level Authorization exposes internal object properties to clients due to insufficient control over serialized data. In real-world terms, CVE-2017-0249 has been described as an elevation of privilege when ASP.NET Core fails to properly sanitize web requests, allowing attackers to access object properties that should remain private. This pattern aligns with CWE-20 (Improper Input Validation) by failing to filter or validate data before returning it in API responses, which can lead to privilege escalation via the object graph. Attackers can exploit this by retrieving or manipulating fields that reveal roles, permissions, or secrets embedded in domain models. When ASP.NET Core controllers return EF Core entities directly or rely on client-provided data to shape responses, sensitive properties (for example IsAdmin, PasswordHash, or internal flags) can be exposed. If a client can influence serialization, binding, or field selection, they may elevate privileges or access resources beyond their authorization. Remediation requires explicit data shaping, strict binding, and server-side authorization controls. Use DTOs or view models for all API outputs, project only the allowed fields, and avoid returning domain models directly. Apply [Bind] to limit input properties, decorate sensitive properties with [JsonIgnore], and consider policy-based or field-level authorization to suppress fields according to user permissions. Ensure your ASP.NET Core version is patched and monitor CVE advisories for related fixes. Additionally, add automated tests that verify sensitive fields are not serialized for inappropriate roles and review your data access patterns to prevent object-property leakage.

Code Fix Example

ASP.NET Core API Security Remediation
Vulnerable code:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

public class User { public int Id { get; set; } public string UserName { get; set; } public string Email { get; set; } public bool IsAdmin { get; set; } public string PasswordHash { get; set; } }

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly AppDbContext _context;
    public UsersController(AppDbContext context) => _context = context;

    [HttpGet("{id}")]
    public async Task<IActionResult> GetUser(int id)
    {
        var user = await _context.Users.FindAsync(id);
        if (user == null) return NotFound();
        // Vulnerable: returns the entire domain model, including sensitive fields
        return Ok(user);
    }
}

// Fixed: shape data and restrict exposure
public class UserDto { public int Id { get; set; } public string UserName { get; set; } public string Email { get; set; } }

[ApiController]
[Route("api/[controller]")]
public class UsersController2 : ControllerBase
{
    private readonly AppDbContext _context;
    public UsersController2(AppDbContext context) => _context = context;

    [HttpGet("{id}")]
    public async Task<IActionResult> GetUser(int id)
    {
        var dto = await _context.Users
            .Where(u => u.Id == id)
            .Select(u => new UserDto { Id = u.Id, UserName = u.UserName, Email = u.Email })
            .FirstOrDefaultAsync();
        if (dto == null) return NotFound();
        return Ok(dto);
    }
}

CVE References

Choose which optional cookies to allow. You can change this any time.