Skip to content

CORS Misconfiguration Testing

4 min read Created Mar 28, 2026 Last updated Apr 24, 2026

CORS misconfigurations allow attacker-controlled origins to make authenticated cross-origin requests to an API. When Access-Control-Allow-Origin reflects an attacker-supplied origin and Access-Control-Allow-Credentials: true is present, a malicious page can read API responses using the victim's session cookies. Detection confirms the misconfiguration exists. Once confirmed, move to CORS exploitation to assess whether sensitive data is accessible through the affected endpoints. CORS and CSRF share the same-origin boundary, so test CSRF detection alongside CORS testing to cover both cross-origin attack surfaces.

  • Reflected origin test sends an arbitrary Origin header and checks if the response mirrors it with credentials allowed.
  • Null origin test checks if the server trusts null, which sandboxed iframes can produce.
  • Subdomain trust test probes whether a compromised or attacker-controlled subdomain is trusted.
  • Multi-endpoint sweep tests all discovered API paths, since CORS policy often differs between endpoints.

Reflected Origin Test

Send an arbitrary Origin header and check whether it is reflected in the response. This is the most common CORS misconfiguration:

┌──(kali㉿kali)-[~]
└─$ curl -skI https://$DOMAIN/api/v1/user -H 'Origin: https://attacker.com' | grep -i 'access-control'
access-control-allow-origin: https://attacker.com
access-control-allow-credentials: true
Explain command
-skI Silent mode, skip TLS verification, fetch response headers only.
-H 'Origin: https://attacker.com' Sets an attacker-controlled Origin header to test CORS reflection.
grep -i 'access-control' Case-insensitive filter for CORS-related response headers.

Reflected origin with credentials allowed is a confirmed exploitable misconfiguration. Any origin can read API responses using the victim's cookies: no restriction is applied. This enables cross-origin reading of profile data, tokens, and other authenticated API responses.

Notice

Note on preflight requests: browsers send a preflight OPTIONS request for non-simple requests (custom headers, non-standard content types, methods other than GET/HEAD/POST). If the server blocks the preflight, the browser never sends the actual request, even when Access-Control-Allow-Origin would reflect the origin. A reflected origin is only exploitable when the request is simple (standard GET with no custom headers) or the server also permits the preflight.

Null Origin Test

Some applications trust a null origin for legacy compatibility. Sandboxed iframes can send null origins, making this exploitable:

┌──(kali㉿kali)-[~]
└─$ curl -skI https://$DOMAIN/api/v1/user -H 'Origin: null' | grep -i 'access-control'
access-control-allow-origin: null
access-control-allow-credentials: true

Subdomain Trust Test

Some applications restrict CORS to subdomains of their own domain. If any subdomain is compromised or has XSS, it can be used to make credentialed cross-origin requests:

┌──(kali㉿kali)-[~]
└─$ curl -skI https://$DOMAIN/api/v1/user -H "Origin: https://evil.$DOMAIN" | grep -i 'access-control'
access-control-allow-origin: https://evil.example.com
access-control-allow-credentials: true
┌──(kali㉿kali)-[~]
└─$ curl -skI https://$DOMAIN/api/v1/user -H "Origin: https://$DOMAIN.attacker.com" | grep -i 'access-control'

A suffix match bypass like example.com.attacker.com being trusted indicates the application uses a vulnerable contains or endsWith check rather than exact origin matching.

Notice

Even when CORS headers are misconfigured, SameSite=Lax cookies (the default in modern browsers) are not sent on cross-origin JavaScript requests. This means the attacker's page cannot read authenticated responses if the session cookie uses SameSite=Lax or Strict. Check the cookie attributes during testing: CORS exploitation requires SameSite=None or legacy browsers that default to None.

Wildcard Without Credentials

A wildcard Access-Control-Allow-Origin: * without Allow-Credentials is not directly exploitable for authenticated requests but confirms the API returns data to any origin: useful for unauthenticated data gathering:

┌──(kali㉿kali)-[~]
└─$ curl -skI https://$DOMAIN/api/v1/public -H 'Origin: https://attacker.com' | grep -i 'access-control'
access-control-allow-origin: *

Test Multiple Endpoints

CORS configuration often differs between endpoints. The main domain may be hardened while API and auth endpoints are not. Test all discovered API paths:

┌──(kali㉿kali)-[~]
└─$ for endpoint in /api/v1/user /api/v1/profile /api/v1/orders /api/v2/account /graphql; do echo -n "$endpoint: "; curl -skI https://$DOMAIN$endpoint -H 'Origin: https://attacker.com' | grep -i 'access-control-allow-origin' | tr -d '\n'; echo; done
/api/v1/user: access-control-allow-origin: https://attacker.com
/api/v1/profile: access-control-allow-origin: *
/api/v1/orders: 
/graphql: access-control-allow-origin: https://attacker.com

References