Setting an overly permissive Cross-Origin Resource Sharing (CORS) policy allows malicious websites to read responses from your application on behalf of authenticated users.
Why is this an issue?
Same-origin policy in browsers prevents JavaScript from
making cross-origin HTTP requests to resources with a different origin (domain, protocol, or port). The Cross-Origin Resource Sharing (CORS) mechanism allows servers to relax this
restriction by including Access-Control-Allow-Origin response headers that tell browsers which origins are permitted.
Setting the Access-Control-Allow-Origin header to a wildcard (*) or dynamically reflecting a user-supplied
Origin header without validation completely disables same-origin protection for the affected resource.
What is the potential impact?
Sensitive data exposure
When CORS restrictions are disabled, a malicious website visited by an authenticated user can issue cross-origin requests to the vulnerable application and read the responses. This allows attackers to steal sensitive data accessible to the victim, such as account details, API keys, or private application data.
Account takeover
If the application is also configured with Access-Control-Allow-Credentials: true, the browser will include cookies and HTTP
authentication headers in cross-origin requests. Attackers can then perform authenticated operations on behalf of the victim, potentially leading to
full account takeover or unauthorized data modification.
How to fix it in ASP.NET Core
Set the Access-Control-Allow-Origin header or configure CORS policies with specific trusted origins, and validate user-supplied
origins against an allow-list.
Code examples
Noncompliant code example
[HttpGet]
public string Get()
{
Response.Headers.Add("Access-Control-Allow-Origin", "*"); // Noncompliant
Response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "*"); // Noncompliant
return "Success";
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("*"); // Noncompliant
});
options.AddPolicy(name: "EnableAllPolicy", builder =>
{
builder.WithOrigins("*"); // Noncompliant
});
options.AddPolicy(name: "OtherPolicy", builder =>
{
builder.AllowAnyOrigin(); // Noncompliant
});
});
services.AddControllers();
}
User-controlled origin:
String origin = Request.Headers["Origin"];
Response.Headers.Add("Access-Control-Allow-Origin", origin); // Noncompliant
Compliant solution
[HttpGet]
public string Get()
{
Response.Headers.Add("Access-Control-Allow-Origin", "https://trustedwebsite.com");
Response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "https://trustedwebsite.com");
return "Success";
}
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("https://trustedwebsite.com", "https://anothertrustedwebsite.com");
});
options.AddPolicy(name: "EnableAllPolicy", builder =>
{
builder.WithOrigins("https://trustedwebsite.com");
});
});
services.AddControllers();
}
User-controlled origin validated with an allow-list:
String origin = Request.Headers["Origin"];
if (trustedOrigins.Contains(origin))
{
Response.Headers.Add("Access-Control-Allow-Origin", origin);
}
How to fix it in ASP.NET MVC 4.x
Set the Access-Control-Allow-Origin header or use the EnableCors attribute with specific trusted origins.
Code examples
Noncompliant code example
public class HomeController : ApiController
{
public HttpResponseMessage Get()
{
var response = HttpContext.Current.Response;
response.Headers.Add("Access-Control-Allow-Origin", "*"); // Noncompliant
response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "*"); // Noncompliant
response.AppendHeader(HeaderNames.AccessControlAllowOrigin, "*"); // Noncompliant
}
}
[EnableCors(origins: "*", headers: "*", methods: "GET")] // Noncompliant
public HttpResponseMessage Get() => new HttpResponseMessage()
{
Content = new StringContent("content")
};
Compliant solution
public class HomeController : ApiController
{
public HttpResponseMessage Get()
{
var response = HttpContext.Current.Response;
response.Headers.Add("Access-Control-Allow-Origin", "https://trustedwebsite.com");
response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "https://trustedwebsite.com");
response.AppendHeader(HeaderNames.AccessControlAllowOrigin, "https://trustedwebsite.com");
}
}
[EnableCors(origins: "https://trustedwebsite.com", headers: "*", methods: "GET")]
public HttpResponseMessage Get() => new HttpResponseMessage()
{
Content = new StringContent("content")
};
Resources
Documentation
- MDN - Cross-Origin Resource Sharing (CORS)
- MDN - Same-origin policy
- OWASP HTML5 Security Cheat Sheet - Cross Origin Resource Sharing
Standards
- OWASP - Top 10 2021 Category A5 - Security Misconfiguration
- OWASP - Top 10 2021 Category A7 - Identification and Authentication Failures
- OWASP - Top 10 2017 Category A6 - Security Misconfiguration
- CWE - CWE-346 - Origin Validation Error
- CWE - CWE-942 - Permissive Cross-domain Security Policy with Untrusted Domains