Having a permissive Cross-Origin Resource Sharing policy is security-sensitive. It has led in the past to the following vulnerabilities:

Same origin policy in browsers prevents, by default and for security-reasons, a javascript frontend to perform a cross-origin HTTP request to a resource that has a different origin (domain, protocol, or port) from its own. The requested target can append additional HTTP headers in response, called CORS, that act like directives for the browser and change the access control policy / relax the same origin policy.

Ask Yourself Whether

There is a risk if you answered yes to any of those questions.

Recommended Secure Coding Practices

Sensitive Code Example

ASP.NET Core MVC:

[HttpGet]
public string Get()
{
    Response.Headers.Add("Access-Control-Allow-Origin", "*"); // Sensitive
    Response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "*"); // Sensitive
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(builder =>
        {
            builder.WithOrigins("*"); // Sensitive
        });

        options.AddPolicy(name: "EnableAllPolicy", builder =>
        {
            builder.WithOrigins("*"); // Sensitive
        });

        options.AddPolicy(name: "OtherPolicy", builder =>
        {
            builder.AllowAnyOrigin(); // Sensitive
        });
    });

    services.AddControllers();
}

ASP.NET MVC:

public class HomeController : ApiController
{
    public HttpResponseMessage Get()
    {
        var response = HttpContext.Current.Response;

        response.Headers.Add("Access-Control-Allow-Origin", "*"); // Sensitive
        response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "*"); // Sensitive
        response.AppendHeader(HeaderNames.AccessControlAllowOrigin, "*"); // Sensitive
    }
}
[EnableCors(origins: "*", headers: "*", methods: "GET")] // Sensitive
public HttpResponseMessage Get() => new HttpResponseMessage()
{
    Content = new StringContent("content")
};

User-controlled origin:

String origin = Request.Headers["Origin"];
Response.Headers.Add("Access-Control-Allow-Origin", origin); // Sensitive

Compliant Solution

ASP.NET Core MVC:

[HttpGet]
public string Get()
{
    Response.Headers.Add("Access-Control-Allow-Origin", "https://trustedwebsite.com"); // Safe
    Response.Headers.Add(HeaderNames.AccessControlAllowOrigin, "https://trustedwebsite.com"); // Safe
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(builder =>
        {
            builder.WithOrigins("https://trustedwebsite.com", "https://anothertrustedwebsite.com"); // Safe
        });

        options.AddPolicy(name: "EnableAllPolicy", builder =>
        {
            builder.WithOrigins("https://trustedwebsite.com"); // Safe
        });
    });

    services.AddControllers();
}

ASP.Net MVC:

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")
};

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);
}

See