How the attack works

Browsers send an Origin header along with cross-origin requests. The server uses the response headers Access-Control-Allow-Origin (ACAO) and Access-Control-Allow-Credentials (ACAC) to decide which foreign origin may read the response and whether cookies/credentials may be sent along with it.

By default, browsers do not send credentials with cross-origin requests (MDN). Misconfigurations arise when the server has one of the following weaknesses:

  • Unchecked reflection: the server reflects the origin supplied by the client back into ACAO without checking it.
  • Flawed whitelist checks: whitelist checks are implemented incorrectly via prefix/suffix/regex matching (e.g. "ends with normal-website.com" also allows the attacker-registered domain hackersnormal-website.com, "starts with normal-website.com" also allows normal-website.com.evil-user.net).
  • Whitelisting null: the server whitelists the special value null, which an attacker can generate via a sandboxed iframe.

If the server additionally sets ACAC: true, the attacker's page can make authenticated requests via fetch/XMLHttpRequest with withCredentials=true and read the victim's response.

Important according to MDN: for requests with credentials, the server must specify a concrete origin instead of the wildcard *. In addition, the Origin header can be freely forged by non-browser clients such as curl, which is why, according to OWASP, it must not be used for authentication.

1. Starting pointAPI reflects the origin or allows credentials too broadly
2. AttackA foreign website sends a request with cookies
3. ResultAuthenticated response gets stolen

Overly permissive CORS lets foreign sites read authenticated data.

Example

Request
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...
Response
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://malicious-website.com
Access-Control-Allow-Credentials: true
...

Impact

A foreign, attacker-controlled website can read authenticated responses from the API on behalf of a logged-in victim, and thereby steal sensitive data such as API keys, CSRF tokens, or personal data.

According to PortSwigger, this can be escalated further:

  • Trust relationships: via trust relationships with an XSS-vulnerable subdomain.
  • Breaking TLS: by breaking TLS, if an HTTP subdomain is considered trusted.
  • Access to the intranet: with ACAO: * without credentials, as access to internal intranet resources by abusing the victim's browser as a proxy.

How to protect against it

  • Never reflect origins from the Origin header without checking them; only enter genuinely trustworthy origins in Access-Control-Allow-Origin (PortSwigger).
  • Perform whitelist checks against the exact, complete origin string, not via prefix/suffix matching or error-prone regex, to rule out bypass domains such as hackersnormal-website.com or normal-website.com.evil-user.net (PortSwigger).
  • Don't whitelist the value null; avoid Access-Control-Allow-Origin: null, since sandboxed/serialized requests can generate it (PortSwigger).
  • Don't use the wildcard * together with credentials - according to MDN, the server must specify a concrete origin for requests with credentials; don't use wildcards on the internet for sensitive/internal resources (MDN, PortSwigger).
  • Don't use the Origin header for authentication, since it can be freely forged by non-browser clients (curl/Wget/Burp) (OWASP).
  • CORS is not a substitute for server-side security: enforce authentication on the accessed resources and enforce session management and protection of sensitive data server-side (PortSwigger, OWASP).

Sources

Keep reading