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.
Overly permissive CORS lets foreign sites read authenticated data.
Example
GET /sensitive-victim-data HTTP/1.1
Host: vulnerable-website.com
Origin: https://malicious-website.com
Cookie: sessionid=...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
- Cross-origin resource sharing (CORS) - Web Security Academy PortSwigger, 2026
- Cross-Origin Resource Sharing (CORS) - HTTP | MDN MDN Web Docs (Mozilla), 2026
- Access-Control-Allow-Origin header MDN Web Docs (Mozilla), 2026
- Access-Control-Allow-Credentials header MDN Web Docs (Mozilla), 2026
- CORS OriginHeaderScrutiny OWASP Foundation, 2026