Overview
The Same-Origin Policy (SOP) is a browser security mechanism that prevents JavaScript on one origin (scheme + host + port) from reading responses from a different origin. The Cross-Origin Resource Sharing (CORS) protocol, defined in the WHATWG Fetch Standard, provides a controlled mechanism to relax this restriction: a server can explicitly declare which foreign origins are allowed to read its responses by setting Access-Control-Allow-Origin and related response headers.
A CORS misconfiguration occurs when a server grants cross-origin access too broadly — for example, reflecting any requested origin, trusting all subdomains without validation, or combining Access-Control-Allow-Origin: * with Access-Control-Allow-Credentials: true in a way that exposes authenticated responses. An attacker who can direct a victim's browser to their site can then read the server's responses as if they were the victim, bypassing the protection the Same-Origin Policy was designed to provide.
How it works
When a browser makes a cross-origin request, it includes an Origin request header. The server's CORS policy determines whether the response is exposed to the requesting script. Common misconfiguration patterns include:
- Origin reflection: The server reads the incoming
Originheader and echoes it back verbatim inAccess-Control-Allow-Origin, combined withAccess-Control-Allow-Credentials: true. Any origin — including a fully attacker-controlled domain — is effectively trusted. - Wildcard with credentials: Returning
Access-Control-Allow-Origin: *alongsideAccess-Control-Allow-Credentials: true. Although browsers reject this combination per the spec, some server-side frameworks do so inadvertently and misconfigured reverse proxies may alter headers downstream. - Weak origin validation: Checking only whether the
Originvalue contains or ends with a trusted string (e.g.,example.com), allowing bypasses viaevil-example.comornotexample.com. - Null origin trust: Allowing
Origin: null, which can be sent by sandboxed iframes, data URIs, and certain redirects — all controllable by an attacker. - Trusting arbitrary subdomains: Allowing
*.example.comwithout considering that a compromised or user-controlled subdomain (e.g., via subdomain takeover) would be implicitly trusted.
Exploitation follows a straightforward cross-site request pattern: the attacker hosts JavaScript on their domain that fetches the target API endpoint, reads the response body (which may contain session tokens, PII, or business-critical data), and exfiltrates it. Because the browser attaches the victim's cookies to the request, the response is fully authenticated.
Business impact
A successfully exploited CORS misconfiguration on an authenticated endpoint can lead to:
- Account takeover: Stealing session tokens, OAuth tokens, or API keys returned in responses.
- Sensitive data exposure: Reading personal data, financial records, internal configuration, or intellectual property from JSON APIs — a direct breach under GDPR, HIPAA, PCI-DSS, and similar regulations.
- Privilege escalation: On internal APIs only accessible to privileged roles, an attacker who tricks an administrator into visiting a malicious page can read admin-only data.
- Reputational and regulatory harm: Data breaches attributable to application-layer misconfigurations are increasingly scrutinised by regulators and carry significant financial penalties.
How to fix it
- Maintain an explicit allowlist of trusted origins. Compare the incoming
Originheader against a server-side set of known-good origins using exact string matching. Never use substring or suffix checks alone. - Never reflect the request
Originheader without validation. If the logic isresponse.setHeader('Access-Control-Allow-Origin', request.headers.origin)without any check, every origin in the world is trusted. - Do not allow the
nullorigin for production endpoints. Treatnullas untrusted unless there is an explicit, documented requirement. - Use a wildcard (
*) only for fully public, unauthenticated resources. Never combineAccess-Control-Allow-Origin: *withAccess-Control-Allow-Credentials: true. - Set
Access-Control-Allow-Credentials: trueonly when strictly necessary and only in conjunction with a specific, validated origin inAccess-Control-Allow-Origin. - Restrict
Access-Control-Allow-MethodsandAccess-Control-Allow-Headersto the minimum set actually required by the application. - Set the
Vary: Originresponse header whenever theAccess-Control-Allow-Originvalue is dynamically computed, so that caches do not serve one origin's response to another. - Audit third-party libraries and reverse proxy configurations (e.g., nginx, API gateways) that may add or override CORS headers independently of application logic.
- Apply CORS policies server-side, not in client-side code. Browser-side workarounds are not a security control.
Sensagraph automatically detects permissive and misconfigured CORS policies during continuous scanning of web applications.
References
- WHATWG Fetch Standard – CORS Protocol
- MDN Web Docs – Cross-Origin Resource Sharing (CORS)
- OWASP – CORS Origin Header Scrutiny
- OWASP WSTG – Testing CORS (WSTG-CLNT-07)
- MITRE CWE-942 – Permissive Cross-domain Policy with Untrusted Domains
- RFC 6454 – The Web Origin Concept
- PortSwigger Web Security Academy – CORS