Dev Tools

CORS Misconfiguration: Security Risks and How to Fix Them

CORS misconfigurations are consistently in the OWASP Top 10. A single wildcard origin can expose your entire API to cross-origin attacks.

๐Ÿ“… May 28, 2026ยทโฑ๏ธ 8 min readยทโœ๏ธ Cikal Studio Labs
๐Ÿ”„

The Same-Origin Policy: Why It Exists

The Same-Origin Policy (SOP) is the most important security boundary in web browsers. It dictates that JavaScript code on one origin (defined by protocol + domain + port) cannot read responses from requests to a different origin. This prevents a fundamental attack scenario: a malicious website using your browser โ€” and your authenticated session cookies โ€” to read your email, bank balance, private messages, or any other data from services you're logged into.

Without SOP, visiting any malicious website would give its JavaScript code the ability to silently read all your data from every other service you're authenticated with โ€” your complete email history, financial account balances, private social media posts, corporate systems, everything. SOP makes this attack impossible by default.

But legitimate applications need to make cross-origin requests. A React frontend on app.company.com needs to call APIs on api.company.com. A JavaScript widget embedded on partner sites needs to communicate with the originating service. CORS (Cross-Origin Resource Sharing) is the standardized mechanism for selectively relaxing SOP in controlled, declared ways โ€” allowing specific trusted origins access while maintaining the security boundary against untrusted origins.

The Anatomy of a CORS Request

Understanding how CORS actually works is prerequisite to understanding how it fails:

  • A browser script on frontend.com makes a request to api.backend.com โ€” a cross-origin request
  • For "simple" requests (GET/POST with standard content types), the browser sends the request immediately and includes an Origin: https://frontend.com header
  • For "non-simple" requests (custom headers, PUT/DELETE, JSON content-type), the browser sends a preflight OPTIONS request first, asking the server whether the actual request is permitted
  • The server responds with CORS headers declaring which origins are allowed, which methods are permitted, and which headers can be used
  • If the server's CORS response permits the requesting origin, the browser allows the JavaScript to read the response
  • If the server doesn't allow the requesting origin, the browser blocks JavaScript from reading the response โ€” even if the request itself was sent and processed by the server

This is a critical security point: CORS controls whether JavaScript can read responses, not whether requests are sent. A CORS misconfiguration that allows response reading to an unauthorized origin is the vulnerability โ€” not the request itself.

The Wildcard Origin: When Access-Control-Allow-Origin: * Is Dangerous

The wildcard Access-Control-Allow-Origin: * tells the browser that any origin can read responses from this server. For truly public APIs returning non-sensitive, non-personalized data (weather information, public transit schedules, static content), wildcard CORS is acceptable and convenient โ€” it allows easy consumption of the API from any origin without configuration.

For authenticated APIs โ€” any API that returns user-specific data, accepts authentication tokens, or performs actions on behalf of authenticated users โ€” wildcard CORS is a critical vulnerability. Here's why it remains dangerous even when the spec prohibits combining wildcard with credentials:

  • Developers sometimes set Access-Control-Allow-Origin: * alongside Access-Control-Allow-Credentials: true through misconfiguration or misunderstanding the spec
  • Some server frameworks incorrectly implement CORS and don't enforce the spec's prohibition on this combination
  • Token-based authentication (where the token is passed in an Authorization header rather than a cookie) can be combined with wildcard CORS in ways that don't violate the spec but still create security risks

Origin Reflection: The Subtle Misconfiguration

Origin reflection is arguably more dangerous than explicit wildcard because it's less obvious and appears to be "working correctly." The misconfigured server reads the Origin header from incoming requests and echoes it back in the Access-Control-Allow-Origin response without validation:

  • Attacker creates a page on evil.com
  • The attacker's page makes a cross-origin authenticated request to api.victim.com, including the victim's session cookie
  • The server receives Origin: https://evil.com and responds with Access-Control-Allow-Origin: https://evil.com โ€” reflecting the attacker-controlled origin
  • The browser sees the CORS header allowing evil.com and allows the attacker's script to read the full response, including sensitive user data

The fix is maintaining an explicit whitelist of allowed origins and only reflecting origins that appear in that whitelist. Reflecting arbitrary origins is functionally equivalent to a wildcard.

Common CORS Misconfigurations and Their Exploitability

A comprehensive CORS misconfiguration catalog:

  • Trusting null origin: Access-Control-Allow-Origin: null โ€” an attacker can create a sandboxed iframe that sends requests with Origin: null, bypassing origin-based restrictions
  • Prefix/suffix matching flaws: Attempting to validate origins with string matching rather than exact comparison. origin.startsWith("https://company.com") would be bypassed by https://company.com.attacker.com
  • Regex matching flaws: ^https://.*.company.com$ should work correctly; .*company.com.* would be bypassed by https://notcompany.com where the period isn't escaped
  • Missing Vary: Origin header: When CORS policy varies by origin, responses must include Vary: Origin to prevent CDN and proxy caches from serving one user's CORS-allowed response to another user from a different origin
  • HTTP origins trusted when HTTPS is used: If your application allows http://yourfrontend.com as a CORS origin, an attacker who can perform a man-in-the-middle attack on the HTTP connection can modify the page to make malicious cross-origin requests

Correct CORS Implementation

The secure CORS implementation pattern:

  1. Maintain an explicit allowlist of approved origins. Store it in configuration, not hardcoded in route handlers.
  2. Validate exactly: Compare the incoming Origin header against the allowlist using exact string matching (case-insensitive). Never use prefix matching or regex unless you've carefully tested for bypass.
  3. Return the matched origin, not a wildcard: If the origin is in your allowlist, return Access-Control-Allow-Origin: [that specific origin].
  4. Always return Vary: Origin when your CORS policy varies by origin.
  5. Handle preflight correctly: Respond to OPTIONS requests with the appropriate CORS headers and a 204 No Content or 200 OK status. Include Access-Control-Max-Age to cache preflight results and reduce preflight overhead.
  6. Restrict allowed methods and headers: Only include methods and headers in Access-Control-Allow-Methods and Access-Control-Allow-Headers that your API actually uses.
  7. Test from multiple unauthorized origins to verify that access is correctly denied. Security testing should include attempts to exploit all common bypass patterns.

Testing CORS Configuration Thoroughly

CORS misconfigurations are notoriously easy to miss in standard security testing because they require testing from the attacker's perspective โ€” making requests from unauthorized origins and verifying that access is correctly denied. A comprehensive CORS security test should verify: that requests from unlisted origins receive a 403 or no CORS headers (not a matching CORS header); that the null origin is not trusted; that origin header values with your domain as a substring but different actual domain are rejected; that HTTP origins are not trusted when your policy requires HTTPS; and that preflight responses correctly restrict allowed methods and headers. Automated CORS policy analyzers perform this systematic testing without requiring manual construction of test requests from each potential bypass angle.

CORS in Multi-Tenant and Microservices Architectures

CORS configuration complexity increases significantly in microservices architectures where multiple backend services with different CORS requirements serve a single frontend application. A common mistake is configuring overly broad CORS policies on internal services that are intended to be called only from specific trusted origins, because "they're only accessible internally." Network-level internal access controls and application-level CORS validation should both be present โ€” defense in depth ensures that a misconfigured network policy doesn't expose internal services to cross-origin attacks. Each service in a microservices architecture should have its own tightly configured CORS policy reflecting its specific trust requirements, rather than inheriting a broad policy from a shared API gateway configuration.

๐Ÿ’ก CORS analyzer tools: A CORS policy analyzer automatically tests for the common misconfigurations โ€” wildcard origins, origin reflection, null origin trust, and prefix/suffix matching flaws โ€” providing a comprehensive policy assessment without manual testing of each bypass pattern individually.