ASP.NET Core  

Preventing CORS Misconfigurations in ASP.NET Core APIs

Cross-Origin Resource Sharing (CORS) is a critical security feature for web applications. It defines how resources hosted on one domain can be accessed by another. When misconfigured, CORS can lead to serious security risks, such as unauthorized access to APIs, data theft, or even complete account compromise.

In this article, we’ll explore how to correctly configure CORS in ASP.NET Core APIs, the common pitfalls that lead to misconfigurations, and best practices to secure your applications.

Why CORS Matters

Modern browsers enforce the Same-Origin Policy, which restricts web pages from making requests to a different domain, protocol, or port. CORS provides a controlled way for servers to relax this restriction and specify which origins are allowed to access resources.

For example

  • Allowed: https://example.com can call https://api.example.com.

  • Blocked: https://attacker.com cannot call https://api.example.com unless CORS allows it.

When developers configure CORS too loosely (e.g.), attackers may exploit the API from malicious websites.

Common CORS Misconfigurations

Using AllowAnyOrigin() with Authentication

builder.Services.AddCors(options =>
{
    options.AddPolicy("OpenPolicy", policy =>
    {
        policy.AllowAnyOrigin()
              .AllowAnyMethod()
              .AllowAnyHeader();
    });
});

This allows any site to call your API, even if cookies, tokens, or credentials are included.

Risk: Attackers can perform Cross-Site Request Forgery (CSRF) or steal user data.

Allowing Credentials with Wildcards

policy.AllowAnyOrigin()
      .AllowCredentials();

This is invalid in ASP.NET Core, but if forced, it opens a massive security hole. Credentials (cookies, Authorization headers) should only be sent to trusted origins.

Overly Broad Allowed Origins

policy.WithOrigins("https://*.example.com");

Wildcard subdomains may unintentionally allow untrusted or user-controlled domains (e.g., evil.example.com).

Forgetting to Restrict Methods/Headers

policy.WithOrigins("https://trusted.com")
      .AllowAnyHeader()
      .AllowAnyMethod();

Over-permissive headers and methods allow attackers to abuse API endpoints in unexpected ways.

Correctly Configuring CORS in ASP.NET Core

Step 1: Define Trusted Origins

Only allow specific, trusted origins that require access to your API.

builder.Services.AddCors(options =>
{
    options.AddPolicy("SecurePolicy", policy =>
    {
        policy.WithOrigins("https://app.example.com", "https://admin.example.com")
              .WithMethods("GET", "POST")        // Only required methods
              .WithHeaders("Content-Type", "Authorization"); // Only necessary headers
    });
});

Step 2: Apply CORS Policy

Apply globally or per controller.

Global Middleware

var app = builder.Build();

app.UseCors("SecurePolicy");

Per Controller

[EnableCors("SecurePolicy")]
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    // Endpoints here
}

Step 3: Handle Credentials Carefully

If your API needs cookies or tokens with cross-origin requests:

policy.WithOrigins("https://app.example.com")
      .AllowCredentials()
      .WithHeaders("Content-Type", "Authorization");

Always restrict origins to exact, trusted domains.

Best Practices to Prevent CORS Misconfigurations

  1. Never use AllowAnyOrigin() in production APIs.

  2. Avoid wildcards in allowed origins, headers, or methods.

  3. Restrict credentials: Only allow them for trusted, exact origins.

  4. Log and monitor preflight requests (OPTIONS) to detect misuse.

  5. Use environment-based policies (e.g., open CORS in dev, strict in production).

    if (app.Environment.IsDevelopment())
    {
        app.UseCors("DevPolicy"); // More permissive
    }
    else
    {
        app.UseCors("SecurePolicy"); // Strict
    }
    
  6. Test your CORS configuration with tools like curl or browser dev tools to confirm restrictions work as intended.

Example: Secure CORS Setup for an API

builder.Services.AddCors(options =>
{
    options.AddPolicy("ApiCorsPolicy", policy =>
    {
        policy.WithOrigins("https://client.example.com")
              .WithMethods("GET", "POST")
              .WithHeaders("Authorization", "Content-Type")
              .AllowCredentials();
    });
});

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

app.UseCors("ApiCorsPolicy");

app.MapControllers();

Conclusion

CORS is a double-edged sword: while it enables legitimate cross-domain requests, a misconfiguration can expose your ASP.NET Core API to severe attacks. By restricting origins, headers, and methods to only what’s necessary and avoiding dangerous patterns like AllowAnyOrigin(), you can ensure your API is both functional and secure.