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

- CVE-2018-0269
- CVE-2017-14460

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

- You don’t trust the origin specified, example: `Access-Control-Allow-Origin: untrustedwebsite.com`.
- Access control policy is entirely disabled: `Access-Control-Allow-Origin: *`
- Your access control policy is dynamically defined by a user-controlled input like `origin` header.

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

## Recommended Secure Coding Practices

- The `Access-Control-Allow-Origin` header should be set only for a trusted origin and for specific resources.
- Allow only selected, trusted domains in the `Access-Control-Allow-Origin` header. Prefer whitelisting domains over blacklisting or allowing any domain (do not use * wildcard nor blindly return the `Origin` header content without any checks).

## 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

- OWASP - Top 10 2021 Category A5 - Security Misconfiguration
- OWASP - Top 10 2021 Category A7 - Identification and Authentication Failures
- developer.mozilla.org - CORS
- developer.mozilla.org - Same origin policy
- OWASP - Top 10 2017 Category A6 - Security Misconfiguration
- OWASP HTML5 Security Cheat Sheet - Cross Origin Resource Sharing
- CWE - CWE-346 - Origin Validation Error
- CWE - CWE-942 - Overly Permissive Cross-domain Whitelist