Mass Assignment Exploit in Aspnet
How Mass Assignment Exploit Manifests in Aspnet
Mass assignment, also known as overposting, is a vulnerability that occurs when an application automatically binds client-supplied data to internal objects without proper filtering. In ASP.NET Core, this typically happens through the model binding system. When a controller action accepts a complex type parameter (such as an entity) from the request body, the default model binder will populate all writable properties that match incoming JSON fields. If the bound type includes properties that should not be settable by the client (e.g., IsAdmin, Balance, or Role), an attacker can supply values for these properties and potentially escalate privileges or corrupt data.
Consider the following vulnerable controller:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; } // Sensitive property
public decimal AccountBalance { get; set; } // Another sensitive property
}
[HttpPost]
public IActionResult Register([FromBody] User user)
{
// Directly adding the bound entity to the context
_context.Users.Add(user);
_context.SaveChanges();
return Ok();
}An attacker can send a JSON payload with IsAdmin or AccountBalance:
{
"username": "attacker",
"password": "p@ssword",
"isAdmin": true,
"accountBalance": 1000000
}Because the User entity has public setters for these properties, the model binder will set them, and the attacker becomes an admin with an inflated balance. This is a classic mass assignment vulnerability.
ASP.NET Core's model binding is powerful but dangerous when used directly with domain entities. The framework does not differentiate between intended and unintended settable properties; it simply maps JSON fields to matching CLR properties. This behavior is consistent across all JSON input formatters (System.Text.Json and Newtonsoft.Json) unless explicitly configured otherwise.
Mass assignment can also occur in PUT or PATCH endpoints. For example, an endpoint that updates a user profile might accept a User object and apply all changes, allowing an attacker to modify fields like Email (if it should be verified) or Role. Even if the endpoint only intends to allow changing Username and Password, binding to the full entity exposes all properties.
The impact of mass assignment is often severe: privilege escalation, unauthorized data modification, and even complete account takeover. It is recognized as Broken Object Property Level Authorization (BOPLA) in the OWASP API Security Top 10 2023 (A04:2023). Many high-profile breaches have involved this vulnerability, such as incidents in major platforms where mass assignment allowed users to gain unauthorized privileges.
Aspnet-Specific Detection
Detecting mass assignment vulnerabilities in ASP.NET APIs involves both manual code review and dynamic security testing. Since the flaw stems from how the server processes incoming data, black-box scanning can effectively identify it by observing the application's behavior when presented with unexpected properties.
Manual Detection: Review controller actions for parameters that are entity models or domain objects accepted directly from the request body (using [FromBody]). Also check for the absence of property whitelisting via the [Bind] attribute or DTOs. For example, any action with a signature like public IActionResult Update([FromBody] Product product) is suspicious if Product contains sensitive fields like Price or IsFeatured.
Dynamic Scanning with middleBrick: middleBrick's Property Authorization check actively tests for mass assignment. It sends a series of requests to each API endpoint, adding extra properties that are not defined in the OpenAPI specification (if available) or that are known to be sensitive (e.g., isAdmin, role, balance). The scanner then analyzes the response and subsequent state to determine if the server accepted and persisted these values.
For instance, for a POST /api/users endpoint, middleBrick might send:
{
"username": "test",
"password": "test123",
"isAdmin": true
}Then it checks the response (e.g., the created user object) for the presence of isAdmin. It may also follow up with a GET /api/users/test to see if the property was stored. If the server reflects the extra property or changes behavior (e.g., the user can access admin endpoints), the scanner flags a mass assignment issue.
Additionally, middleBrick analyzes the OpenAPI/Swagger specification. If the request schema for an endpoint includes sensitive properties (like isAdmin), that is a strong indicator of a potential mass assignment vulnerability, especially if the endpoint is unauthenticated or the property is not meant to be client-controlled. The scanner resolves all $ref references to get the full picture.
Because middleBrick performs unauthenticated black-box scanning, it tests the API exactly as an external attacker would. The scan completes in 5–15 seconds and produces a detailed report with the affected endpoints, the injected properties, and severity ratings.
Aspnet-Specific Remediation
The definitive fix for mass assignment in ASP.NET Core is to never bind request data directly to entity or domain models. Instead, use dedicated Data Transfer Objects (DTOs) that expose only the properties that clients are allowed to set. This approach is often called the "view model" pattern.
Using DTOs: Create a separate class for input that contains only the intended fields. Then map the DTO to your entity manually or with a library like AutoMapper.
public class CreateUserDto
{
public string Username { get; set; }
public string Password { get; set; }
// No IsAdmin, AccountBalance, etc.
}
[HttpPost]
public async Task CreateUser([FromBody] CreateUserDto dto)
{
var user = new User
{
Username = dto.Username,
Password = dto.Password,
// IsAdmin remains false (default), AccountBalance remains 0
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
return Ok();
} This ensures that even if an attacker includes isAdmin in the JSON, it will be ignored because CreateUserDto has no such property. The model binder will simply discard unknown properties by default (unless configured otherwise).
Whitelisting with [Bind]: For simple cases, you can use the [Bind] attribute to specify which properties are allowed. However, this attribute is not recommended for complex scenarios because it only works on simple types and can be error-prone. Example:
[HttpPost]
public IActionResult CreateUser([Bind("Username,Password")] User user)
{
// Only Username and Password will be bound; other properties remain default.
...
}Note: The [Bind] attribute does not protect against nested objects. If User has a complex property like Address, all properties of Address would be bindable unless you also restrict them.
PATCH Endpoints: For partial updates, use JsonPatchDocument with a DTO that defines which fields can be patched. Example:
[HttpPatch("{id}")]
public async Task UpdateUser(int id, [FromBody] JsonPatchDocument<UpdateUserDto> patchDoc)
{
if (patchDoc == null) return BadRequest();
var user = await _context.Users.FindAsync(id);
if (user == null) return NotFound();
var dto = new UpdateUserDto();
patchDoc.ApplyTo(dto, ModelState);
if (!ModelState.IsValid) return BadRequest(ModelState);
// Apply allowed changes
if (!string.IsNullOrEmpty(dto.Username))
user.Username = dto.Username;
if (!string.IsNullOrEmpty(dto.Password))
user.Password = dto.Password;
await _context.SaveChangesAsync();
return NoContent();
} Here, UpdateUserDto might only have Username and Password. Even if the patch document tries to modify IsAdmin, it will be ignored because the DTO lacks that property.
Additional Measures: In Startup.cs, you can configure the JSON serializer to ignore extra properties entirely by setting JsonSerializerOptions.DefaultIgnoreCondition. By default, System.Text.Json ignores extra properties, which helps but the key is to not have sensitive properties in the bound type. Also, consider making sensitive properties have private setters in the entity, but this may interfere with EF Core. The DTO pattern is a robust and widely recommended solution.
After remediation, retest with middleBrick to ensure the Property Authorization check no longer reports mass assignment issues. The scanner will confirm that extra properties are rejected or ignored.