Prototype Pollution in Aspnet with Bearer Tokens
Prototype Pollution in Aspnet with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Prototype pollution in ASP.NET applications becomes particularly relevant when APIs rely on Bearer token authentication. In this context, the API endpoint accepts a Bearer token in the Authorization header and uses claims from the token (such as roles or scopes) to make authorization decisions. If the application deserializes or merges untrusted input—such as JSON from the request body, query strings, or headers—into objects that are later compared against or merged with token-derived data, attackers can inject properties that affect object prototypes or logic used for access control.
Consider an endpoint that reads a user’s roles from a JWT Bearer token and also accepts a JSON payload specifying roles for a resource. If the application merges the token claims into the payload object without proper validation, an attacker can submit a request like { "__proto__": { "isAdmin": true } }. In JavaScript-based runtime behavior (e.g., when Node.js interop or legacy ASP.NET integrations use dynamic objects), this can pollute shared object templates, leading to privilege escalation when authorization checks incorrectly evaluate the polluted prototype chain. In .NET, similar issues arise when using dictionaries or ExpandoObjects where injected keys like __lookupGetter__ or constructor alter expected behavior in downstream logic.
Additionally, Bearer token scopes or roles used in policy evaluation can be influenced if the application deserializes user-controlled data into objects that participate in authorization decisions. For example, if an endpoint uses User.IsInRole based on token claims and also processes a request body that gets merged into a role collection, an attacker can supply { "roles": ["admin"] } to escalate privileges. This becomes a prototype pollution vector when the runtime or libraries treat merged objects as templates for further operations. In ASP.NET Core, using System.Text.Json with JsonDocument can mitigate some risks, but naive merging of JsonElement with dictionaries or custom models can still expose the attack surface.
SSRF and external data exposure can compound these issues: an attacker might use a Bearer token-protected endpoint to make the server fetch malicious external resources that contain polluted templates or exfiltrate token-related data. Input validation must therefore treat Bearer token metadata and request body data as distinct trust zones. The 12 parallel security checks in middleBrick—including Authentication, BOLA/IDOR, Input Validation, and Unsafe Consumption—help detect such combinations by correlating runtime behavior with OpenAPI/Swagger specs, including $ref resolutions across definitions.
Bearer Tokens-Specific Remediation in Aspnet — concrete code fixes
Remediation focuses on strict separation of token-derived data and user input, and avoiding unsafe merging or deserialization patterns. Always validate and whitelist properties before merging objects, and prefer immutable data structures.
Example 1: Safe model binding in ASP.NET Core without merging token claims into request objects.
// Controller action with separate token claims and request model
[Authorize]
[HttpPost("/resources")]
public IActionResult UpdateResource(Guid resourceId, [FromBody] ResourceUpdateRequest request)
{
// Token claims are available via User, but not merged into request
var userRoles = User.Claims.Where(c => c.Type == "role").Select(c => c.Value).ToList();
// Apply business logic using request only, not polluted prototypes
if (!HasPermission(userRoles, request.Action))
{
return Forbid();
}
// Safe update logic
return Ok();
}
public class ResourceUpdateRequest
{
public string Action { get; set; }
public string Target { get; set; }
// No __proto__ or constructor allowed by model validation
}
Example 2: Using System.Text.Json with custom options to ignore polymorphic deserialization and disallow property injection.
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
// Prevent creating ExpandoObject or dynamic objects from JSON
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
};
// Explicitly deserialize into a known type
var update = JsonSerializer.Deserialize<ResourceUpdateRequest>(jsonString, options);
if (update == null) { return BadRequest(); }
Example 3: Rejecting dangerous property names at the model validation level.
[ApiController]
[Route("[controller]")]
public class ResourcesController : ControllerBase
{
[HttpPost]
public IActionResult Create([FromBody] ResourceModel model)
{
// Explicit validation to block prototype pollution keys
var blockedKeys = new[] { "__proto__", "constructor", "prototype" };
if (model.AdditionalProperties?.Keys.Any(blockedKeys.Contains) == true)
{
return BadRequest("Invalid properties");
}
// Proceed with safe logic
return CreatedAtAction(nameof(Get), new { id = model.Id }, model);
}
}
middleBrick’s CLI can validate these patterns by scanning unauthenticated endpoints and checking whether OpenAPI specs align with runtime behavior. Use middlebrick scan <url> from the terminal to identify risky endpoints that merge token claims with untrusted input. The GitHub Action can enforce thresholds in CI/CD, while the Web Dashboard and MCP Server help track findings and integrate scans into developer workflows.