Introduction
Your organization has migrated critical services to .NET Core, attracted by its performance and cross-platform capabilities. The APIs handle sensitive financial data and user credentials. Then your security team discovers that attackers have been exploiting a mass assignment vulnerability to escalate privileges—modifying their own role claims by including unexpected properties in JSON requests.
.NET Core APIs face distinct security challenges around model binding, authorization policies, and input validation. Unlike traditional ASP.NET, the framework favors explicit configuration over convention. This guide covers essential hardening practices for .NET Core APIs, common vulnerability patterns, and how AI-agentic testing validates your security implementation.
Understanding the Risk
.NET Core API vulnerabilities often emerge from implicit trust in request data and insufficient authorization enforcement.
Mass Assignment (Over-posting): Model binding automatically maps request properties to object properties:
// Vulnerable: Binds all properties from request
[HttpPost]
public async Task<IActionResult> UpdateUser([FromBody] User user)
{
// Attacker sends: { "name": "John", "role": "Admin", "isVerified": true }
await _context.SaveChangesAsync();
return Ok();
}Insecure Direct Object References (IDOR): APIs that expose database IDs without ownership verification:
// Vulnerable: No ownership check
[HttpGet("documents/{id}")]
public async Task<IActionResult> GetDocument(int id)
{
var document = await _context.Documents.FindAsync(id);
return Ok(document); // Returns any document regardless of owner
}SQL Injection via Raw Queries: Raw SQL queries can introduce injection vulnerabilities:
// Vulnerable: String interpolation in raw SQL
var users = _context.Users
.FromSqlRaw($"SELECT * FROM Users WHERE Department = '{department}'")
.ToList();Prevention Best Practices
Use DTOs to Prevent Mass Assignment
Create specific DTOs for each operation, exposing only allowed properties:
public class UserUpdateDto
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[EmailAddress]
public string Email { get; set; }
}
[HttpPut("profile")]
[Authorize]
public async Task<IActionResult> UpdateProfile([FromBody] UserUpdateDto dto)
{
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
var user = await _context.Users.FindAsync(userId);
user.Name = dto.Name;
user.Email = dto.Email;
await _context.SaveChangesAsync();
return Ok();
}Enforce Authorization Policies
Define granular authorization policies and apply them consistently:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
options.AddPolicy("DocumentOwner", policy =>
policy.Requirements.Add(new DocumentOwnerRequirement()));
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
[HttpDelete("documents/{id}")]
[Authorize(Policy = "DocumentOwner")]
public async Task<IActionResult> DeleteDocument(int id)
{
await _documentService.DeleteAsync(id);
return NoContent();
}Secure Database Queries
Always use parameterized queries with Entity Framework:
// Safe: Parameterized query
var users = await _context.Users
.FromSqlRaw("SELECT * FROM Users WHERE Department = {0}", department)
.ToListAsync();
// Safe: LINQ queries are automatically parameterized
var users = await _context.Users
.Where(u => u.Department == department)
.ToListAsync();Configure Security Headers
Add security headers middleware:
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("Content-Security-Policy",
"default-src 'self'; script-src 'self'");
await next();
});Implement Rate Limiting
Protect against brute force and denial of service:
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("auth", limiterOptions =>
{
limiterOptions.PermitLimit = 5;
limiterOptions.Window = TimeSpan.FromMinutes(15);
});
});
[HttpPost("login")]
[EnableRateLimiting("auth")]
public async Task<IActionResult> Login([FromBody] LoginDto dto)
{
// Authentication logic
}Secure JWT Authentication
Configure JWT validation properly:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ClockSkew = TimeSpan.Zero
};
});Why Traditional Pentesting Falls Short
.NET Core APIs involve complex interactions between model binding, authorization policies, middleware, and Entity Framework. Manual testers may identify obvious issues but struggle to comprehensively test all endpoints against various authentication states, role combinations, and input permutations.
How AI-Agentic Testing Solves It
RedVeil's AI agents systematically probe .NET Core APIs for mass assignment, IDOR, injection vulnerabilities, and authorization bypass. The platform tests each endpoint with various authentication contexts and malformed inputs, validating that security controls work as intended.
On-demand testing allows validation after each deployment or configuration change. When RedVeil identifies vulnerabilities, it provides clear reproduction steps and evidence.
Conclusion
.NET Core provides robust security capabilities, but they require deliberate implementation. Mass assignment, authorization gaps, and input validation failures create significant attack surface when not addressed properly. Following established patterns for DTOs, authorization policies, and parameterized queries substantially reduces risk.
AI-agentic testing validates that your security implementation actually protects against attacks, catching configuration mistakes and logic flaws that code review might miss.
Harden your .NET Core APIs with RedVeil—begin your security assessment.