Cross origin resource sharing (CORS)
CORS (Cross-Origin Resource Sharing) — guide for web hacking / defender awareness
Cross-Origin Resource Sharing (CORS) is a browser mechanism that enables controlled access to resources located outside of a given domain.
SOP (Same Origin Policy) = locks on your house to stop neighbours from sneaking in.
CORS = special permission keys so a friendly neighbour can visit.
Misconfigured CORS = giving a key to anyone who says they are your friend even if they're not.
What is CORS
Imagine two houses:
House A: example.com
House B: otherwebsite.com
Normally, if you live in House A, you can't just walk into House B's living room and read their private letters. This is the Same Origin Policy (SOP) — it keeps things safe and private.
CORS is like giving House B a special key:
House B gives permission: "Hey browser, it's okay for House A to read certain things in my house if they come with a key."
Why use CORS
Sometimes websites need to share data — e.g., example.com wants to ask weather.com for a forecast.
CORS lets browsers relax SOP rules so example.com can talk to weather.com in a controlled way.
Where does the vulnerability come from?
Common misconfigurations and issues:
Bad configuration: trusting any origin (Access-Control-Allow-Origin: * + credentials true)
Analogy: Putting a sign on your front door “Everyone welcome — even with keys to the safe inside.”
Trusting user input (reflecting Origin header without validation)
Analogy: Letting anyone who says "I'm John" in without checking.
Trusting any subdomain (loose suffix matching)
Analogy: Trusting anyone whose last name is "Advisor" — you trust EvilAdvisor too.
Trusting weird origins like null
Analogy: Letting in anyone who says they’re from nowhere.
Ignoring protocol (allowing http origins for https site)
Analogy: Letting a safe be opened by a key coming via an unlocked bicycle (HTTP).
Forgetting Vary: Origin (cache poisoning)
Analogy: Leaving your mailbox open; a stranger plants fake letters.
Real-world example (high level)
A crypto exchange loads sensitive info (API key) on the account page via AJAX when a user is logged in.
If the exchange incorrectly trusts and reflects the Origin header (or whitelists null, wildcards, or insecure subdomains) and Allow-Credentials is enabled, then a malicious site can cause a logged-in victim’s browser to request that endpoint and read the response — exfiltrating the API key.
Diagrams (conceptual):
Normal Safe Case:
User at example.com → Browser blocks request (SOP) → bitcoin.com: "No, you can’t ask me!"
Dangerous CORS Misconfiguration:
Attacker site attacker.com pretends to be trusted → bitcoin.com API responds with secrets → attacker steals API key.
lab: CORS vulnerability with basic origin reflection
Introduction
Scenario: penetration tester inspects a crypto exchange that loads private info via AJAX after login.
Issue: server reflects the Origin header without strict validation, allowing attacker-controlled origin values.
Impact: if victim visits malicious page, their browser will include session cookies (withCredentials: true), and the server will allow the response to be read by the malicious origin.
Why the exploit works:
Server trusts arbitrary Origin (reflects attacker-supplied value).
Allow-Credentials enabled: victim's session cookies included.
Victim's browser exposes sensitive API key to attacker's site.
Real-world impact:
Account takeover, data leakage, bypass of authentication protections.
Whitelisted null origin explanation (analogy)
Office allows guests if name/address are on guest list (SOP).
They also allow people who write "No Address" (Origin: null) for devs/local files.
Attackers can write "No Address" and be let in, then access secure file room and exfiltrate documents.
Mapping:
"No Address" = Origin: null
Security guard = server's CORS policy
File room = sensitive endpoint
Sneaking copies out = sending stolen data to attacker site
Attacker disguise = sandboxed iframe or other trick that causes Origin: null
lab: CORS vulnerability with trusted null origin
Introduction
Scenario: server’s CORS policy whitelists the null origin (often for local development).
Attack: force the victim’s browser to send a request with Origin: null (e.g., sandboxed iframe). If the server allows such requests with credentials, the attacker can retrieve and exfiltrate sensitive data.
Why the exploit works:
Null origin whitelisted.
Browser includes cookies (allow-credentials).
Sandboxed iframe causes Origin: null.
Real-world impact:
Sensitive data theft, account compromise, SOP bypass via null origin.
Exploiting XSS via CORS trust relationships (high level)
Analogy:
Bank stores spare vault key at a trusted subdomain.
If that subdomain has an XSS (broken lock), an attacker can steal the spare key and access the main vault.
Mapping:
Bank vault = sensitive API endpoint (/api/requestApikey)
Spare key at friend’s house = CORS trust to subdomain
Broken lock = XSS on subdomain
Thief using the key = attacker JS on subdomain pulling data from main site
Even if main site is secure, trusting an insecure subdomain to store access is risky.
Breaking TLS with poorly configured CORS (high level)
Analogy:
Main system uses HTTPS locked vans. Trusted subdomain uses HTTP bicycles without locks.
A network attacker (MITM) intercepts the HTTP bicycle traffic, tampers with requests, and gets the main service to send vault documents to the attacker.
Mapping:
Locked vans = HTTPS
Bicycle without locks = HTTP subdomain
Mail thief controlling the road = MITM attacker
Vault documents = sensitive API response
Main post office trusting bicycle = CORS whitelist including HTTP origin
Trusting insecure (HTTP) origins in CORS can allow MITM-based exfiltration of otherwise HTTPS-protected data.
lab: CORS vulnerability with trusted insecure protocols (HTTP subdomain)
Introduction
Scenario: site trusts all subdomains regardless of HTTPS/HTTP. Attacker finds an HTTP subdomain with XSS, injects JS, and uses CORS trust to read data from main HTTPS site.
Vulnerability — problem
Source: CORS trusts all subdomains, including insecure HTTP ones.
Sink: Access-Control-Allow-Credentials: true sends victim cookies.
Challenge: inject JS into HTTP subdomain to read sensitive data from the secure main site.
End goal
Steal admin API key from /accountDetails via XSS on an HTTP subdomain exploiting CORS trust.
Reconnaissance plan
Log in, observe /accountDetails returns API key.
Test
Origin: http://subdomain.lab-idand confirm server reflects it in ACAO.Find a product page on HTTP subdomain vulnerable to XSS (productId parameter).
Attack — crafting the exploit
Example attack flow: inject JS on HTTP subdomain to make a CORS request to the HTTPS main site and exfiltrate result:
Good:
Only allow trusted sites (no reflection or fuzzy matches)
Do not reflect the Origin header blindly. Use an exact allowlist (scheme + host + port).
Good example (Node/Express):
Never whitelist null
Browsers send Origin: null from file:, data:, sandboxed iframes. Do not accept null for sensitive endpoints. Use explicit dev origins like https://localhost:3000 instead.
Bad:
Avoid wildcards on internal networks
Do not use ACAO: * for sensitive or internal APIs.
Bad:
Good:
Remember: CORS ≠ server-side security
CORS controls what browsers can read. It does not replace authentication, authorization, CSRF protections, rate limiting, or session management.
Other best practices:
Enforce HTTPS (reject http:// origins).
Minimize allowed methods/headers:
Add Vary: Origin when ACAO is dynamic to prevent cache poisoning.
Keep server-side protections (authN/authZ, CSRF, rate limiting).
Quick checklist:
Exact allowlist (scheme+host+port), no reflection.
No wildcards (*) for sensitive endpoints.
No null origin whitelisting.
Enforce HTTPS only origins.
Tighten methods/headers; preflight responds 204.
Vary: Origin when ACAO is dynamic.
Keep server-side auth and protections active.
Example snippets and tests
Good server response for authenticated endpoints (example):
Bad patterns to avoid:
Echoing req.headers.origin without validation.
Allowing
Access-Control-Allow-Origin: nullfor production.Using
Access-Control-Allow-Origin: *on sensitive endpoints.
Quick curl tests:
Minimal Nginx strict allowlist (concept):
Spring Boot strict CORS (concept):
Attack ↔ Defense quick map (summary)
ACAO: * on sensitive endpoints → risk: any site can read it → defense: exact trusted origin(s) only.
Reflecting Origin without validation → risk: full data exfiltration → defense: exact allowlist (scheme+host+port).
Whitelisting null → risk: sandbox/file/data abuse → defense: never allow null in production.
Allowing HTTP origins → risk: MITM/HTTPS bypass → defense: HTTPS-only origins.
Missing Vary: Origin with dynamic ACAO → risk: cache poisoning → defense: set Vary: Origin.
Over-permissive methods/headers → risk: expanded attack surface → defense: minimize to required.
Relying on CORS as auth → risk: direct API abuse → defense: keep robust authN/authZ and CSRF protections.
Final checklist (concise)
Exact allowlist (scheme+host+port); no reflection.
No wildcards (*) for sensitive endpoints.
No null origin whitelisting.
HTTPS-only origins; reject http://.
Tighten methods/headers; preflight responds 204.
Vary: Origin when ACAO is dynamic.
Keep server-side auth/CSRF/authorization/rate limits.
Last updated