CORS Misconfiguration
A complete guide to understanding, detecting, exploiting, and preventing CORS Misconfiguration vulnerabilities.
Introduction
Cross-Origin Resource Sharing (CORS) Misconfiguration
ANAS EDUCATION -- Bug Bounty & Pentesting Course (V2 Beginner-First)
SECTION 1. Introduction
Imagine you open your PC and visit `portal.anasbank.com`.
This is your bank's customer portal. The login page lives at `portal.anasbank.com`. The actual data (your accounts, balances, transactions) is served by an API at a different subdomain: `api.anasbank.com`. The browser treats those two as different origins because the hostnames differ.
You sign in. The server sends back a session cookie:
The portal's JavaScript then loads your account data by calling the API:
When the browser sees a cross-origin call, it asks one question before letting the page READ the response: "did the API consent to this origin reading the response?" That consent is communicated in two HTTP headers on the API response:
If `Access-Control-Allow-Origin` (ACAO) matches the page's origin and `Access-Control-Allow-Credentials` (ACAC) is `true`, the browser delivers the response body to the page's JavaScript. If not, the browser blocks the read and prints a CORS error in the developer console. Normal. Expected.
Now look at the same picture again, but with a question on top of it: what if the API echoes back whatever origin the page claims, instead of checking against an allowlist?
A small startup that wants to support multiple frontends might wire up its API like this:
The server takes whatever `Origin` header the browser sent and writes it straight into the response. From the developer's perspective, this "just works" -- the legitimate frontend at `portal.anasbank.com` always gets `Access-Control-Allow-Origin: https://portal.anasbank.com` back, and the page loads.
An attacker now stands up a small page at `https://evil.example` containing this JavaScript:
A victim who is logged into AnasBank in tab A clicks a link or sees an ad that opens `https://evil.example` in tab B. The evil page's JavaScript fires a `fetch` to `api.anasbank.com`. Because `credentials: 'include'` is set and the session cookie's domain matches, the browser attaches the victim's session cookie. The API sees the request with valid credentials and replies:
The API reflected the attacker's origin verbatim. The browser checks: does ACAO match the requesting page's origin? Yes (`https://evil.example` matches itself). Is ACAC true? Yes. The browser hands the JSON to the evil page's JavaScript. The evil page forwards it to the attacker's logger. The attacker now has the victim's email, balance, and API key.
No password was stolen. No XSS was needed. The victim only had to visit one attacker-controlled page while a separate AnasBank tab was open. The bug is the API's policy of trusting any `Origin` the browser sends.
This is CORS misconfiguration. The bug class where a server's Cross-Origin Resource Sharing policy is wired in a way that lets untrusted origins read authenticated responses.
This course teaches the CORS bug class from zero. By the end you will know:
- ●What the Same-Origin Policy (SOP) is and how CORS relaxes it.
- ●The two killer headers (`Access-Control-Allow-Origin` and `Access-Control-Allow-Credentials`) and the precise combinations that are dangerous.
- ●The four families of CORS misconfig: reflected Origin, trusted `null`, weak whitelist regex, trusted insecure protocols.
- ●The 12 most reliable bypass and exploitation techniques.
- ●Prevention with strict exact-match allowlists and `Vary: Origin`.
You do not need to be an HTTP expert. You need to understand that CORS is the door, not the wall, and that the wall (SOP) only holds if the door is locked properly.
SECTION 2. How It Works
To find these bugs you first need to understand the Same-Origin Policy and what CORS does to it.
Step 1. The Same-Origin Policy (SOP)
The Same-Origin Policy is the browser's foundational security boundary. It says: a script running on one origin cannot read responses from a different origin. An origin is the triple `(scheme, host, port)`.
SOP is the wall. Without it, any random page on the internet could fetch your Gmail inbox the moment your browser had its session cookie.
Step 2. Why CORS exists
Modern apps split their UI and their APIs across origins. Without CORS, the legitimate UI at `portal.anasbank.com` could not read its own API at `api.anasbank.com`. CORS is the consent protocol that lets a server say: "I am OK with these specific origins reading my responses."
Step 3. The handshake
The browser is the enforcer. The server merely declares its policy via the ACAO and ACAC headers; the browser uses those headers to decide whether to deliver the body to the page's JavaScript.
Step 4. Preflight (for non-simple requests)
If the request uses methods other than GET/POST/HEAD, or a non-simple `Content-Type` (anything other than `application/x-www-form-urlencoded`, `multipart/form-data`, `text/plain`), or custom headers, the browser sends an OPTIONS preflight first:
The server replies with allowed methods and headers; the browser then sends the real request only if the preflight passed. This is what stops a `<form>` on `evil.example` from POSTing JSON to an API: the JSON content type triggers a preflight, which the API can refuse.
Step 5. The two killer headers
Together they form the "credentialed CORS" combination. Misconfigure either, and the wall breaks down differently:
Step 6. Where the bug lives
Step 2 is where developers ship the bug. Reflecting Origin verbatim, trusting `null`, broken regex, trusting HTTP subdomains, or wildcard ACAO on authenticated endpoints all live there.
Step 7. CORS is not authentication
CORS controls who can READ a response. It does not authenticate the requester. The attacker's page can SEND a request to the API; the browser will attach cookies if SameSite and credentials policy allow. What CORS controls is whether the attacker's JavaScript gets to SEE the body of the response. This is the central thing to understand: a CORS misconfig is not "the API stopped checking sessions"; it is "the API let the attacker page read the authenticated user's data."
SECTION 3. Attack Flow
The walkthrough below shows a complete reflected-origin attack against a SaaS API.
Step 1: Recon
Identify the API host (typically `api.target.com`). Catalog every authenticated endpoint that returns sensitive data: `/me`, `/account`, `/profile`, `/billing`, `/api-keys`, `/messages`, `/integrations`.
Step 2: Capture a baseline
Log in to the legit frontend. Capture the normal request to a sensitive endpoint in Burp Proxy. Note the response's ACAO and ACAC headers.
Step 3: Probe Origin reflection
In Burp Repeater, change the `Origin` header to `https://evil.example` and resend the request with the victim's cookie. Inspect the response.
Look for:
If both appear, the endpoint reflects arbitrary origins with credentials. CRITICAL.
Step 4: Walk the variations
- ●`Origin: null` (sandboxed-iframe vector).
- ●`Origin: http://target.com` (insecure-protocol trust).
- ●`Origin: https://target.com.evil.com` (suffix-match bypass).
- ●`Origin: https://eviltarget.com` (substring-match bypass).
- ●`Origin: https://target.com\.evil.com` (regex parsing quirk).
Any successful reflection or trust is a finding.
Step 5: Build the PoC
Host an exploit page at an attacker-controlled domain (or use `ngrok`):
Step 6: Deliver
Send the link to a logged-in victim (phishing email, malvertising, social engineering, watering hole on a trusted subdomain).
Step 7: Capture impact
Victim's browser fetches the API with their cookie; API replies with ACAO matching evil.example + ACAC true; browser hands the response to the evil page's JS; evil page logs to attacker's collector.
Step 8: Escalate
Use the leaked API key to call the API directly with no browser involvement: drain balance, exfiltrate all data, modify account state.
ASCII timing diagram
SECTION 4. Why Developers Make This Mistake
CORS misconfiguration is a mental-model error about what SOP and CORS actually do.
Mistake 1: "CORS is security"
False. CORS RELAXES security. SOP is the security boundary. CORS is the consent protocol that lets a server selectively open the wall to specific trusted origins. Misconfigured CORS removes the wall; it does not add one.
Mistake 2: "Only my frontend can send my origin"
False. The browser does not let JavaScript SET arbitrary `Origin` headers, but tools like curl, Burp, fetch from a different page, and any HTTP client can send any Origin. The defense must be server-side allowlisting, not trust in the browser.
Mistake 3: "If I echo Origin back, only the requester sees the response"
False. The browser sees ACAO, sees that it matches the requesting origin, and hands the response to that origin's JavaScript. If the requesting origin is `evil.example`, the response goes to `evil.example`.
Mistake 4: "I copied this from StackOverflow"
The most common cause. The "accepted answer" for "fix CORS error" is often:
This is the textbook critical CORS misconfig.
Mistake 5: "I use a regex allowlist, that is safe"
Naive regex matching produces predictable bypasses:
- ●`endsWith('target.com')` -> `eviltarget.com` passes.
- ●`startsWith('https://target.com')` -> `https://target.com.evil.com` passes.
- ●`includes('target.com')` -> `https://target.com.evil.com` passes.
- ●Regex without anchors -> attacker controls the matching portion.
- ●Regex with unescaped dots -> `targetXcom` matches `target.com`.
Mistake 6: "I only trust subdomains of target.com"
HTTP subdomains can be MITM'd or carry forgotten XSS. Subdomain takeover lets an attacker claim a subdomain that the CORS policy trusts.
Mistake 7: "ACAO: * is the same as restricting nothing"
With `ACAC: true`, browsers REJECT the wildcard combination. Without `ACAC: true`, the wildcard still lets any page on the internet read the response (no credentials, but if the data is sensitive without auth, that is the bug).
Mistake 8: "WebSockets and GraphQL follow the same CORS rules"
WebSockets do NOT follow CORS; they follow an `Origin` handshake at upgrade time, which has its own pitfalls (Cross-Site WebSocket Hijacking, CSWSH). GraphQL endpoints often have separate CORS configs from REST endpoints on the same host.
SECTION 5. Beginner Summary
- ●CORS controls which web origins are allowed to READ the responses of your API in a browser. It does NOT prevent attackers from SENDING requests.
- ●A misconfiguration that reflects whatever `Origin` the browser sent, combined with `Access-Control-Allow-Credentials: true`, lets any attacker page read authenticated responses from logged-in victims.
- ●The two killer headers are `Access-Control-Allow-Origin` (which origin may read) and `Access-Control-Allow-Credentials` (whether cookies travel and the response can be read for that origin).
- ●Detection is one Burp Repeater swap: change `Origin: https://target.com` to `Origin: https://evil.example` and look at the response headers. Reflection + ACAC true = critical.
- ●Prevention is one rule: a strict, exact, hardcoded allowlist of trusted origins; never reflect; never trust `null`; never use `*` with credentials; set `Vary: Origin`.
SECTION 6. Visual Explanation
Same-Origin Policy wall
Safe vs vulnerable CORS
Four families of CORS misconfig
Detection cheat lines
SECTION 7. Definition
Technical definition
CORS misconfiguration is a vulnerability in which a server's Cross-Origin Resource Sharing policy is implemented in a way that grants untrusted origins permission to send credentialed requests AND read the responses. It breaks the Same-Origin Policy by allowing the attacker's page to read authenticated data that should be restricted to trusted origins.
- ●CWE-942: Permissive Cross-domain Policy with Untrusted Domains
- ●CWE-346: Origin Validation Error
- ●OWASP Top 10 (2021): A05 Security Misconfiguration (also A01 in some mappings)
- ●Alternate names: CORS abuse, ACAO reflection, cross-origin data theft.
Beginner-friendly definition
CORS misconfiguration is when a website's API politely tells any random attacker page on the internet: "Sure, take a look at my logged-in users' private data."
Why it matters
CORS misconfigurations leak API keys, session data, PII, and admin credentials. They are common, often invisible to scanners, and routinely earn high bug bounty payouts. Notable disclosures:
- ●James Kettle / PortSwigger (2016) -- "Exploiting CORS misconfigurations for Bitcoins and Bounties": https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties. A major Bitcoin exchange's account API reflected `Origin` with credentials; chained to wallet drain.
- ●Truffle Security "of-CORS" research (2023): https://trufflesecurity.com/blog/of-cors. Internal-network CORS abuse via typosquatting domains and service workers; demonstrated impactful misconfigurations on Tesla and other large corporate networks.
- ●Ayoub Safa "Think Outside the Scope" (2019): https://infosecwriteups.com/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397. Domain-name parsing tricks for bypassing weak server-side validation.
- ●Google VRP: CORS reflections in 404 pages and error endpoints disclosed and rewarded.
- ●CWE-942 listing in the MITRE CWE top-25 affected projects database; CORS bugs continue to appear yearly.
Common affected systems
- ●SaaS dashboards with API subdomains.
- ●Single Page Applications backed by JSON APIs.
- ●Banking and fintech APIs.
- ●E-commerce account and order APIs.
- ●Mobile-app backends shared with web frontends.
- ●Internal microservices exposed via gateway.
- ●GraphQL endpoints (often separate CORS config).
- ●WebSocket endpoints (CSWSH, related class).
- ●Any API that uses cookie-based auth across subdomains.
SECTION 8. Examples
Example 1. AnasBank reflected-Origin account API
The feature. The login portal at `portal.anasbank.com` reads account data from `api.anasbank.com/account/details`. The API was wired up with `res.header('Access-Control-Allow-Origin', req.headers.origin)` plus `Access-Control-Allow-Credentials: true`.
The bug. No allowlist. The API echoes back any Origin.
The attack step by step.
- ●Step 1: an attacker hosts `evil.example/poc.html` containing `fetch('https://api.anasbank.com/account/details', { credentials: 'include' })`.
- ●Step 2: link is sent to victims via phishing or malvertising.
- ●Step 3: victims who are logged in to AnasBank visit the page.
- ●Step 4: browser fires the fetch with the victim's session cookie; API replies with `ACAO: https://evil.example` and `ACAC: true`; browser delivers the body to evil.example's JS.
- ●Step 5: API key + balance + email leak to the attacker.
Example 2. AnasDocs null-Origin trust
The feature. AnasDocs's API was tested locally during development with `file://` documents (which send `Origin: null`). The team added `null` to the allowlist to make local testing work and never removed it.
The bug. `Access-Control-Allow-Origin: null` plus `ACAC: true` is exploitable through sandboxed iframes (which the browser sends with `Origin: null`).
The attack step by step.
- ●Step 1: attacker hosts a page with a sandboxed iframe.
- ●Step 2: iframe's Origin is `null`; API trusts it; browser delivers the body.
- ●Step 3: victim's data leaks.
Example 3. AnasMarket weak regex allowlist
The feature. AnasMarket's API matches origins with `if (origin.endsWith("anasmarket.com")) allow`.
The bug. String-suffix matching accepts any registered domain that ends with the trusted string.
The attack step by step.
- ●Step 1: attacker registers `evil-anasmarket.com`.
- ●Step 2: hosts the PoC there.
- ●Step 3: server's `endsWith` returns true; reflection succeeds.
Other variants of weak matching produce different bypass shapes:
- ●`startsWith('https://anasmarket.com')` -> `https://anasmarket.com.evil.example` passes.
- ●`includes('anasmarket.com')` -> any URL containing the substring passes.
- ●Regex without anchors -> `https://attacker.com#https://anasmarket.com` may pass (depending on regex).
- ●Regex with unescaped dots -> `anasmarketXcom` matches.
Example 4. AnasCorp HTTP subdomain pivot
The feature. AnasCorp's main app is HTTPS-only. A legacy stock-tracker subdomain `stock.anascorp.com` runs HTTP. The API's CORS allowlist includes all `*.anascorp.com` over any protocol.
The bug. The HTTP subdomain is trivially MITM-able on hostile networks and historically carries a reflective XSS the team forgot to patch.
The attack step by step.
- ●Step 1: attacker triggers the XSS on `http://stock.anascorp.com` via a crafted URL.
- ●Step 2: the XSS payload fires a credentialed `fetch` to the HTTPS API.
- ●Step 3: API trusts the `http://stock.anascorp.com` origin and reflects it; browser delivers the body to the XSS payload.
- ●Step 4: data is exfiltrated.
Example 5. AnasOne wildcard on internal API
The feature. AnasOne runs an internal HR microservice on `hr.internal.anasone.local`. The team set `Access-Control-Allow-Origin: *` because "only employees on the corporate network can reach it anyway."
The bug. Wildcard ACAO means any web page in any employee's browser can read the response. Even without credentials, if the data is sensitive (which it is), the bug exists.
The attack step by step.
- ●Step 1: attacker tricks an HR analyst (on the corporate network) into visiting `https://evil.example`.
- ●Step 2: page fires fetches at `http://hr.internal.anasone.local/employees`.
- ●Step 3: requests reach the internal API because the browser is on the corporate network.
- ●Step 4: wildcard ACAO lets the evil.example page read the response.
- ●Step 5: full employee records leak.
(Truffle Security's `of-CORS` tool weaponizes this pattern with typosquatted domains and service workers; see section 17.)
SECTION 9. Vulnerable Code
Node.js (Express) -- reflected Origin
The textbook critical CORS misconfig.
Python (Flask) -- reflected Origin
PHP -- null trusted
If the incoming `Origin: null`, the server replies `ACAO: null`. Sandboxed iframes win.
Java (Spring) -- bad regex allowlist
The wildcards in `allowedOriginPatterns` admit attacker-controlled domains containing the trusted substring.
Java (Spring Security) -- allow-any
Modern browsers reject the combination of `*` and credentials, but if developers fix the runtime error by switching to "reflect arbitrary origin," they ship the reflection bug instead.
C# (ASP.NET Core) -- IsOriginAllowed lambda
A frequent regression: developer hit a runtime error from `AllowAnyOrigin().AllowCredentials()`, "fixed" it with `SetIsOriginAllowed(_ => true)`, and shipped the same bug in a different shape.
Go (gorilla/mux) -- reflection
Ruby on Rails -- rack-cors permissive
The universal pattern
- ●1. Server receives a request with an `Origin` header.
- ●2. Server either (a) reflects it verbatim, (b) matches it against a broken regex, (c) trusts `null`, (d) trusts HTTP subdomains, or (e) sets wildcard while still trusting credentials.
- ●3. Server returns `Access-Control-Allow-Origin: <attacker-controllable>` and `Access-Control-Allow-Credentials: true`.
- ●4. Browser hands the authenticated response to attacker JS.
Step 2 is where the bug is born.
SECTION 10. Detection
Manual workflow
- ●Step 1: log into the target. Catalog authenticated endpoints that return sensitive data: `/me`, `/account`, `/profile`, `/billing`, `/api-keys`, `/messages`, `/integrations`.
- ●Step 2: capture a normal request in Burp Proxy. Inspect the response's ACAO and ACAC headers.
- ●Step 3: in Repeater, modify the `Origin` header and resend with the victim's cookie. Try the six probe variations:
- ●Step 4: look at the response headers:
- ●If `Access-Control-Allow-Origin` matches your probe AND `Access-Control-Allow-Credentials: true` is present, the endpoint is critically vulnerable.
- ●If `Access-Control-Allow-Origin: null` is reflected, the sandboxed-iframe vector applies.
- ●If `Access-Control-Allow-Origin: *` is set on an authenticated endpoint, browsers will refuse to send credentials but the endpoint may still be reachable without auth.
- ●Step 5: confirm impact with a real exploit page hosted on an attacker-controlled domain.
Burp Suite
- ●Burp Active Scanner catches basic reflected-origin issues.
- ●CORS Misconfiguration Scanner (BApp) by James Kettle automates origin manipulation.
- ●Param Miner can fuzz origins in bulk.
- ●Always confirm in Repeater manually before reporting.
Automated tools
- ●CORScanner (Python): https://github.com/chenjj/CORScanner
- ●Corsy (Python): https://github.com/s0md3v/Corsy
- ●CORStest (research-grade, Ruhr-Universität Bochum): https://github.com/RUB-NDS/CORStest
- ●of-CORS (Truffle Security, internal-network CORS testing via typosquatting): https://github.com/trufflesecurity/of-cors
- ●Custom Python scripts using `requests` to scan dozens of origin variations.
Quick command-line probe
Indicators of vulnerability
- ●`Access-Control-Allow-Origin` reflects whatever value you send in `Origin`.
- ●`Access-Control-Allow-Credentials: true` is present on sensitive endpoints.
- ●`ACAO: null` ever appears.
- ●`ACAO: *` on internal APIs or APIs that do not require auth.
- ●Endpoint returns JSON containing API keys, tokens, balances, or PII.
- ●API is on a different subdomain than the frontend.
- ●Allowlist looks generated from a regex or string functions (`endsWith`, `startsWith`, `includes`).
Train your eye. Every `Origin` header is an invitation.
SECTION 11. Exploitation
Workflow
- ●1. Identify a sensitive authenticated endpoint.
- ●2. Confirm reflection / null trust / weak whitelist.
- ●3. Confirm `ACAC: true`.
- ●4. Build an exploit HTML page on an attacker domain.
- ●5. Deliver via phishing, malvertising, watering hole, or shared-link trick.
- ●6. Capture stolen data on the attacker's collector.
- ●7. Demonstrate impact (account takeover, fund transfer, PII dump).
Techniques
1. Reflected Origin
The classic. The server reflects whatever Origin the page claims.
2. Null Origin via sandboxed iframe
Browsers send `Origin: null` from sandboxed iframes, `data:` URLs, `file://` documents, and cross-origin redirects in some browsers. Exploit:
3. Suffix-match bypass (endsWith)
Server: `if (origin.endsWith('target.com')) allow`. Attacker: register `eviltarget.com`, set `Origin: https://eviltarget.com`. Passes.
4. Prefix-match bypass (startsWith)
Server: `if (origin.startsWith('https://target.com')) allow`. Attacker: set `Origin: https://target.com.evil.example`. Passes.
5. Substring-match bypass (includes)
Server: `if (origin.includes('target.com')) allow`. Attacker: set `Origin: https://target.com.evil.example` or `https://target-com.evil.example` if the regex is malformed.
6. Unanchored regex bypass
Server: regex without `^...$` anchors and unescaped dots. Attacker: domains like `https://targetXcom.evil.example` match `target.com`.
7. Special-character parsing quirks
Some servers parse Origins inconsistently from browsers:
Browser sends the literal string in Origin; server's URL parser strips characters differently. Reference: Ayoub Safa "Think Outside the Scope" (2019).
8. HTTP-subdomain pivot via XSS
The server trusts `http://stock.target.com`. The HTTP subdomain has XSS. Chain:
The XSS executes on the trusted HTTP subdomain. The fetch reaches the HTTPS API with credentials. ACAO trusts the HTTP subdomain. Browser shares response with XSS payload.
9. Wildcard without credentials, but data is sensitive
When `ACAO: *` and `ACAC: false`, the browser refuses to attach cookies. But if the endpoint returns sensitive data without requiring auth (debug endpoints, internal employee info, financial summaries without auth, internal IP ranges), the wildcard is still a critical disclosure path.
10. Internal-network CORS abuse (of-CORS pattern)
When a victim's browser is on a corporate network, an attacker page can reach internal IPs and hostnames the attacker cannot reach directly. If internal APIs use `ACAO: *` or trust corporate domains broadly, the attacker's external page can read internal data through the victim's browser. Truffle Security's `of-CORS` tool weaponizes this with typosquatted domains and service workers.
11. Subdomain takeover + CORS
If `*.target.com` is trusted by CORS and one subdomain is abandoned (DNS CNAME points to a deleted Heroku app, S3 bucket, GitHub Pages), claim it via subdomain takeover. Now your attacker-controlled subdomain is trusted by CORS.
12. Cache poisoning + CORS
If a CDN caches responses including their ACAO header, you can poison the cache with an attacker-friendly origin. The poisoned cache entry is then served to legitimate users. Browser still validates ACAO against the visiting user's origin, so this is rarely a direct CORS bypass on its own, but combined with other quirks it has produced real-world bugs.
13. Cross-Site WebSocket Hijacking (CSWSH)
WebSocket connections do NOT follow CORS; they follow an `Origin` check at the upgrade handshake. If the server checks `Origin` weakly (or not at all), attacker pages can open authenticated WebSocket sessions from cross-origin contexts.
14. Preflight confusion
Some servers respond to OPTIONS with strict CORS but to the actual GET/POST with loose CORS. Send a simple request directly (GET, or POST with `text/plain`) and bypass the preflight enforcement.
15. CORS to CSRF chain (state-changing endpoints)
Some servers misconfigure CORS to allow methods like PUT/DELETE plus arbitrary headers. Combined with credentials, attackers can perform state-changing actions cross-origin. Reference: PortSwigger "CORS to CSRF" patterns.
Common mistakes
- ●Reporting CORS reflection without showing authenticated impact -- triagers downgrade these.
- ●Forgetting `credentials: 'include'` in the PoC.
- ●Confusing a CORS error in DevTools with a bug. The error means SOP is doing its job; the BUG is when there is no error.
- ●Not trying `null` Origin via sandboxed iframes.
- ●Skipping the regex-bypass variations.
- ●Not testing GraphQL and WebSocket endpoints separately from REST.
SECTION 12. Proof of Concept
Burp detection
Reflected Origin HTML PoC
XMLHttpRequest variant
Null-Origin exploit (sandboxed iframe)
HTTP-subdomain pivot via XSS
Python detection script
Bash one-liner
Node.js PoC
PowerShell PoC
Hosting the PoC
Use the resulting public URL as your attacker origin.
CORScanner / Corsy
SECTION 13. Payloads
CORS "payloads" are Origin-header variations plus the JavaScript that reads the response.
Basic Origin payloads
Intermediate (whitelist bypass)
Advanced parsing tricks
JavaScript exploit templates
SECTION 14. Wordlists and Payload Libraries
- ●PayloadsAllTheThings -- CORS Misconfiguration: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration
- ●HackTricks -- CORS bypass: https://hacktricks.wiki/en/pentesting-web/cors-bypass.html
- ●PortSwigger Web Security Academy -- CORS: https://portswigger.net/web-security/cors
- ●PortSwigger Research -- Exploiting CORS misconfigurations for Bitcoins and bounties: https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties
- ●Truffle Security -- of-CORS: https://trufflesecurity.com/blog/of-cors
- ●Ayoub Safa "Think Outside the Scope": https://infosecwriteups.com/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
- ●Intigriti -- CORS guide: https://www.intigriti.com/researchers/blog/hacking-tools/exploiting-cors-misconfiguration-vulnerabilities
- ●CORScanner: https://github.com/chenjj/CORScanner
- ●Corsy: https://github.com/s0md3v/Corsy
- ●CORStest (RUB research): https://github.com/RUB-NDS/CORStest
- ●of-CORS (Truffle Security tool): https://github.com/trufflesecurity/of-cors
- ●Burp Suite CORS BApps -- search Burp BApp Store for "CORS" and "Active Scan++"
- ●MDN -- CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- ●MDN -- Same-Origin Policy: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
- ●OWASP -- CORS OriginHeaderScrutiny: https://owasp.org/www-community/attacks/CORS_OriginHeaderScrutiny
- ●Anas Magane Pentesting Notes -- CORS: https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP
Practical advice
- ●Always test at least the six Origin variations on every authenticated endpoint.
- ●Keep a personal list of 12 Origin parsing tricks for quick spray testing.
- ●Maintain a few realistic decoy HTML pages (newsletter, contest, free trial) to wrap PoCs for delivery-readiness.
- ●Build a Burp macro that auto-rotates Origin values across a request.
SECTION 15. Impact
Step 1: response body theft
The fundamental impact: attacker page reads authenticated response data.
Step 2: API key / token exfiltration
Many endpoints return long-lived API keys; once exfiltrated, the attacker calls the API directly with no browser involvement.
Step 3: account takeover
Endpoints that expose email or password-reset tokens enable full ATO.
Step 4: financial loss
Banking, fintech, crypto: reading account details enables fund transfers (PortSwigger's 2016 Bitcoin exchange disclosure).
Step 5: PII mass exposure
SaaS dashboards with `*.target.com` CORS misconfig leak every tenant's data.
Step 6: internal network exposure
Internal APIs with wildcard or broad CORS allow external pages to read internal data through employee browsers (of-CORS pattern).
Step 7: lateral movement
API keys for one service often unlock chained services (single SSO, shared credentials).
Step 8: WebSocket hijacking
CSWSH: persistent authenticated WebSocket sessions hijacked from attacker pages.
Step 9: cloud-credential theft
Internal endpoints sometimes return AWS/GCP credentials in JSON responses; CORS misconfig leaks them.
Step 10: regulatory and contractual fallout
GDPR, HIPAA, PCI DSS, SOC2 violations once authenticated data is exfiltrated.
Step 11: long-tail cost
Forensics, audits, mandatory disclosures, insurance premium spikes, churn from enterprise customers.
SECTION 16. Prevention
The fix is structural: a strict, exact, hardcoded allowlist of trusted origins; never reflect; never trust `null`; never use `*` with credentials.
Vulnerable example
Safe example (Express)
Key changes:
- ●Strict, exact, hardcoded allowlist.
- ●No regex, no `endsWith`, no `includes`.
- ●`Vary: Origin` so CDNs cache per-origin.
- ●Never reflect `null`.
- ●Never set `ACAO: *` with `ACAC: true`.
Safe example (Flask)
Safe example (Spring Boot)
Use `allowedOrigins` (exact list), not `allowedOriginPatterns` (wildcard-capable).
Safe example (ASP.NET Core)
`WithOrigins(...)` is exact-match; do NOT use `SetIsOriginAllowed(_ => true)`.
Six rules to eliminate CORS misconfig
- ●1. Hardcode a strict allowlist of exact origins (full scheme + host + port).
- ●2. Never reflect the `Origin` header without comparing it against the allowlist.
- ●3. Never trust `null` as an origin.
- ●4. Never trust HTTP origins when the main app is HTTPS.
- ●5. Never use `*` ACAO on authenticated endpoints, even without credentials.
- ●6. Always set `Vary: Origin` to prevent cache poisoning.
Secure coding practices
- ●Use SameSite cookies (`SameSite=Strict` or `Lax`) as defense in depth.
- ●Limit allowed methods and headers to the minimum needed.
- ●Use CSP alongside CORS as defense in depth.
- ●Never copy CORS code from a forum without security review.
Developer checklist
- ●Strict allowlist of exact origins.
- ●No reflection of arbitrary Origins.
- ●No `null` in the allowlist.
- ●No HTTP origins if the main app is HTTPS.
- ●No wildcard ACAO on authenticated endpoints.
- ●`Vary: Origin` always set.
- ●SameSite cookies set.
- ●Preflight responses match real responses (no looser).
- ●CORS policy reviewed by security on every new endpoint.
- ●Internal APIs use precise origins even on internal networks.
- ●GraphQL endpoint has its own explicit CORS policy.
- ●WebSocket endpoint validates `Origin` on upgrade handshake.
Enterprise mitigations
- ●API Gateway-level CORS with policy as code (Kong, Apigee, AWS API Gateway).
- ●Service-mesh CORS in Istio or Linkerd for internal microservices.
- ●WAF rules to detect Origin-header anomalies (unusual ports, suspicious TLDs).
- ●Telemetry on outgoing ACAO header values in production; alert on unexpected reflections.
- ●Bug bounty programs routinely scoped to include CORS misconfigurations.
- ●SAST rules that flag `req.headers.origin` reflected into ACAO, `SetIsOriginAllowed(_ => true)`, `allowedOriginPatterns("*")`, and `Rack::Cors origins '*'` with credentials.
SECTION 17. Real-World Cases
Foundational research
- ●PortSwigger / James Kettle (2016): "Exploiting CORS misconfigurations for Bitcoins and Bounties": https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties. The original whitepaper. A major Bitcoin exchange's account API reflected `Origin` with `ACAC: true`; chained to wallet drain via API-key theft. Patched within 20 minutes of disclosure.
- ●Ayoub Safa "Think Outside the Scope" (2019): https://infosecwriteups.com/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397. Moroccan researcher disclosed advanced URL-parsing bypasses that escalate "unexploitable" CORS reflections into critical bugs.
- ●Truffle Security "of-CORS" (2023): https://trufflesecurity.com/blog/of-cors. Internal-network CORS abuse via typosquatting and service workers. Demonstrated impactful misconfigurations on Tesla and other large corporate networks. Tool: https://github.com/trufflesecurity/of-cors.
- ●Web Application Hacker's Handbook, James Kettle research blogposts and PortSwigger Academy materials.
Real disclosed reports and incidents
- ●PortSwigger 2016 Bitcoin exchange disclosure -- API-key theft via reflected Origin; exchange patched within 20 minutes. Public writeup: https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties.
- ●Google VRP -- CORS reflections in error pages and 404s rewarded under Google's VRP; demonstrates even FAANG ships CORS bugs.
- ●Artsy.net insecure CORS API -- `api.artsy.net` was publicly disclosed reflecting arbitrary origins with credentials; user-data leakage. Classic reflection without allowlist.
- ●CS Money -- Site-wide CORS on Safari due to misconfig, HackerOne disclosed, paid $300.
- ●Coinbase -- "Set as primary" CORS account-level action, paid $100 (HackerOne disclosure).
- ●VK.com -- CORS to email-set on account (HackerOne corpus).
- ●Truffle Security on Tesla -- of-CORS demonstrated internal-network CORS misconfigurations on Tesla's infrastructure.
- ●HackerOne corpus -- CORS reports: https://hackerone.com/hacktivity?queryString=CORS.
- ●CORS misconfiguration on multiple GitHub Pages-hosted apps -- typosquatting-style takeovers led to CORS-trusted attacker subdomains.
CWE references
- ●CWE-942 Permissive Cross-domain Policy with Untrusted Domains: https://cwe.mitre.org/data/definitions/942.html
- ●CWE-346 Origin Validation Error: https://cwe.mitre.org/data/definitions/346.html
- ●CWE-284 Improper Access Control (umbrella for many CORS bugs): https://cwe.mitre.org/data/definitions/284.html
Lessons learned
- ●Reflected-origin bugs ship at every scale, from startups to FAANG.
- ●Bug bounty payouts for credentialed CORS regularly reach four to five figures on top programs.
- ●Internal corporate networks are a treasure trove of CORS bugs via the of-CORS pattern.
- ●CORS is rarely the only bug in a codebase; where one exists, more await on adjacent endpoints (GraphQL, WebSockets).
- ●The fix is always the same: strict exact allowlist.
SECTION 18. References
- ●PortSwigger Web Security Academy -- CORS: https://portswigger.net/web-security/cors
- ●PortSwigger Research -- Exploiting CORS misconfigurations: https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties
- ●MDN -- CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
- ●MDN -- Same-Origin Policy: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
- ●OWASP -- CORS OriginHeaderScrutiny: https://owasp.org/www-community/attacks/CORS_OriginHeaderScrutiny
- ●OWASP Cheat Sheet -- Cross-Site Request Forgery (CORS interplay): https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
- ●CWE-942: https://cwe.mitre.org/data/definitions/942.html
- ●CWE-346: https://cwe.mitre.org/data/definitions/346.html
- ●CWE-284: https://cwe.mitre.org/data/definitions/284.html
- ●Intigriti -- CORS guide: https://www.intigriti.com/researchers/blog/hacking-tools/exploiting-cors-misconfiguration-vulnerabilities
- ●PayloadsAllTheThings -- CORS: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/CORS%20Misconfiguration
- ●Think Outside the Scope (Ayoub Safa, 2019): https://infosecwriteups.com/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397
- ●Truffle Security -- of-CORS: https://trufflesecurity.com/blog/of-cors
- ●of-CORS tool: https://github.com/trufflesecurity/of-cors
- ●HackTricks CORS: https://hacktricks.wiki/en/pentesting-web/cors-bypass.html
- ●CORScanner: https://github.com/chenjj/CORScanner
- ●Corsy: https://github.com/s0md3v/Corsy
- ●CORStest: https://github.com/RUB-NDS/CORStest
- ●HackerOne CORS Hacktivity: https://hackerone.com/hacktivity?queryString=CORS
- ●Anas Magane Pentesting Notes -- CORS: https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP
SECTION 19. Practical Labs
Planned ANAS CORS Labs (SOON)
- ●ANAS-CORS-01 -- AnasBank Reflected Origin Account API (steal API key), beginner
- ●ANAS-CORS-02 -- AnasDocs Null Origin Trust (sandboxed iframe attack), beginner-intermediate
- ●ANAS-CORS-03 -- AnasMarket endsWith Suffix-Match Bypass, intermediate
- ●ANAS-CORS-04 -- AnasMarket startsWith Prefix-Match Bypass, intermediate
- ●ANAS-CORS-05 -- AnasOne includes() Substring-Match Bypass, intermediate
- ●ANAS-CORS-06 -- AnasCorp HTTP Subdomain Pivot via XSS, advanced
- ●ANAS-CORS-07 -- AnasMarket Wildcard ACAO on Internal Debug API, intermediate
- ●ANAS-CORS-08 -- AnasCorp Subdomain Takeover + CORS Trust Chain, advanced
- ●ANAS-CORS-09 -- AnasOne Cross-Site WebSocket Hijacking (CSWSH), advanced
- ●ANAS-CORS-10 -- AnasMarket Preflight vs Real Request Mismatch, advanced
- ●ANAS-CORS-11 -- AnasCorp Internal Network of-CORS Style (typosquat + service worker), expert
- ●ANAS-CORS-12 -- AnasDocs Special-Character Parsing Quirks (backslash, backtick, RTL), expert
- ●ANAS-CORS-13 -- AnasMarket GraphQL Separate CORS Misconfig, advanced
- ●ANAS-CORS-14 -- AnasMarket CDN Cache Poisoning + CORS Origin Header, expert
- ●ANAS-CORS-15 -- AnasBank End-to-End ATO via CORS + Password Reset Token Read, expert
PortSwigger Web Security Academy CORS labs
- ●CORS vulnerability with basic origin reflection (APPRENTICE): https://portswigger.net/web-security/cors/lab-basic-origin-reflection-attack
- ●CORS vulnerability with trusted null origin (APPRENTICE): https://portswigger.net/web-security/cors/lab-null-origin-whitelisted-attack
- ●CORS vulnerability with trusted insecure protocols (PRACTITIONER): https://portswigger.net/web-security/cors/lab-breaking-https-attack
Self-hosted lab targets
- ●Vulnerable Express CORS demo apps on GitHub.
- ●Burp Suite training environments for CORS.
- ●OWASP Juice Shop -- multiple CORS-adjacent challenges: https://github.com/juice-shop/juice-shop.
Lab progression
- ●Week 1: PortSwigger Apprentice CORS labs + ANAS-CORS-01/02 + sections 1-8.
- ●Week 2: PortSwigger Practitioner CORS lab + ANAS-CORS-03 to 06 + read 5 disclosed reports.
- ●Week 3: ANAS-CORS-07 to 10 + practice with CORScanner and Corsy.
- ●Week 4: ANAS-CORS-11/12 + dive into of-CORS internal-network testing.
- ●Week 5: ANAS-CORS-13 to 15 + start hunting on programs that scope CORS explicitly.
SECTION 20. Cheat Sheet
SECTION 21. Exam
Thirty multiple-choice questions. Answer key at the end.
- ●1. What does CORS stand for?
A) Cross-Origin Resource Sharing B) Cross-Origin Request Security C) Controlled Origin Resource System D) Common Origin Reference Source
- ●2. The Same-Origin Policy is:
A) A browser feature that allows scripts to read responses from any domain B) A browser feature that blocks scripts from reading responses across origins C) A server feature that restricts incoming requests D) A firewall rule
- ●3. Which combination is the most dangerous CORS misconfiguration?
A) ACAO reflected + ACAC: true B) ACAO: * without credentials C) ACAO: https://target.com hardcoded D) ACAO not set
- ●4. Browsers REJECT which CORS combination outright?
A) Hardcoded ACAO + ACAC: true B) ACAO: * + ACAC: true C) ACAO: null + ACAC: false D) ACAO not set
- ●5. Which `Origin` value is triggered by a sandboxed iframe?
A) http://evil.com B) null C) * D) https://attacker.com
- ●6. Which CWE most closely matches CORS misconfiguration?
A) CWE-79 B) CWE-89 C) CWE-942 D) CWE-22
- ●7. James Kettle's 2016 CORS research demonstrated theft of:
A) Credit card numbers B) Bitcoins from a crypto exchange C) Government documents D) Healthcare records
- ●8. Different origins include all of the following EXCEPT:
A) https://a.target.com vs https://b.target.com B) https://target.com vs http://target.com C) https://target.com:443 vs https://target.com:8443 D) https://target.com vs https://target.com/path
- ●9. The purpose of a CORS preflight request is:
A) To compress headers B) To check whether the server allows the actual request before sending it C) To authenticate the user D) To validate cookies
- ●10. The fetch property that tells the browser to send cookies cross-origin is:
A) credentials: 'include' B) cookies: 'true' C) sendCredentials: true D) cors: true
- ●11. Modifying the Origin to `https://evil.example` and seeing `ACAO: https://evil.example` plus `ACAC: true` means:
A) Secure B) Critically vulnerable to reflected-origin CORS C) Wildcard D) Properly configured
- ●12. The `Vary: Origin` header is important because:
A) It tells the browser to ignore Origin B) It prevents CDN cache poisoning on CORS responses C) It blocks all CORS requests D) It is required for credentials
- ●13. A naive `endsWith("target.com")` allowlist is bypassed by:
A) https://target.com B) https://eviltarget.com C) https://attacker.com D) https://target.org
- ●14. A naive `startsWith("https://target.com")` allowlist is bypassed by:
A) http://target.com B) https://target.com C) https://target.com.evil.example D) https://target.org
- ●15. Which exploit technique uses a sandboxed iframe?
A) Reflected-origin attack B) Null-origin attack C) Wildcard attack D) CSRF attack
- ●16. Trusting an HTTP subdomain when the main app is HTTPS is dangerous because:
A) HTTP is slower B) HTTP traffic can be MITM'd and HTTP subdomains often carry forgotten XSS that pivots to the HTTPS API C) HTTP cannot send cookies D) HTTPS does not support CORS
- ●17. Which tool is built for internal-network CORS testing via typosquatting?
A) Nmap B) of-CORS C) sqlmap D) hashcat
- ●18. Wildcard ACAO on an internal API is dangerous because:
A) Browsers always send credentials anyway B) Victims on the internal network can be tricked into reading internal data via attacker pages C) It is a syntax error D) Wildcards always include credentials
- ●19. Which exploit pattern combines XSS on a trusted HTTP subdomain with CORS abuse on the HTTPS API?
A) Reflected-origin B) Null-origin C) Protocol-trust pivot D) Wildcard exploit
- ●20. The BEST defense against CORS misconfiguration is:
A) Increase rate limits B) Strict hardcoded allowlist of trusted origins C) Disable CORS entirely D) Use HTTP only
- ●21. Cross-Site WebSocket Hijacking (CSWSH) bypasses CORS because:
A) WebSockets do not follow CORS; they follow a separate Origin handshake at upgrade time B) WebSockets are always encrypted C) WebSockets are forbidden cross-origin D) WebSockets ignore cookies
- ●22. `Access-Control-Allow-Origin: *` with `Access-Control-Allow-Credentials: true` behaves how in modern browsers?
A) Accepted, credentials sent B) REJECTED outright C) Shares response, but not cookies D) Cached forever
- ●23. Which header makes a request "non-simple" and triggers a CORS preflight?
A) User-Agent B) Content-Type: application/json C) Accept-Language D) Referer
- ●24. A SaaS API responds with `ACAO: null`. The most realistic exploitation is via:
A) Direct fetch from attacker domain B) A sandboxed iframe loaded from attacker page C) A POST form D) DNS rebinding
- ●25. An internal API with `ACAO: *` returning sensitive unauthenticated data:
A) None, no credentials B) Attacker pages can read the data through victim browsers on the corporate network C) Always low risk D) Admin-only
- ●26. The payload that tests for null-origin trust is:
A) Origin: https://evil.com B) Origin: null C) Origin: * D) Origin: localhost
- ●27. Subdomain takeover plus CORS chain works when:
A) The CORS policy trusts arbitrary origins B) The CORS policy trusts *.target.com and one subdomain CNAMEs to a deleted service C) The browser disables CORS D) The API uses no auth
- ●28. Best-practice CORS allowlist:
A) Regex with endsWith B) Strict exact set of fully qualified origins C) Reflect Origin always D) Wildcard with credentials
- ●29. A CORS error in DevTools when an evil page tries to read the API means:
A) A critical bug found B) Same-Origin Policy is working; this is the normal secure behavior C) The server is offline D) The browser is broken
- ●30. The MOST important takeaway about CORS:
A) CORS is the security boundary B) CORS relaxes the Same-Origin Policy; SOP is the security C) CORS replaces authentication D) CORS is server-side authorization
Answer key
- ●1.A 2.B 3.A 4.B 5.B 6.C 7.B 8.D 9.B 10.A
- ●11.B 12.B 13.B 14.C 15.B 16.B 17.B 18.B 19.C 20.B
- ●21.A 22.B 23.B 24.B 25.B 26.B 27.B 28.B 29.B 30.B
Scoring
- ●27 to 30: expert.
- ●24 to 26: solid.
- ●19 to 23: functional; re-read sections 11 and 16.
- ●Below 19: re-read sections 1 to 8 and retake.
SECTION 22. Certificate Requirements
- ●Read all 24 sections.
- ●Score 24/30 or higher on section 21.
- ●Complete all PortSwigger Web Security Academy CORS labs (3 labs).
- ●Complete at least 10 of the 15 planned ANAS CORS labs (once released).
- ●Demonstrate one end-to-end credentialed CORS read against a controlled target you own (reflected Origin or null Origin).
- ●Document one finding in a 500+ word write-up with HTTP traces, the bypass that worked, and the exact fix.
- ●Maintain a personal payload library of 20+ Origin variations organized by tier.
Ethical baseline
The techniques here read real authenticated data. Use them only on systems you own or have explicit written permission to test. Hosting a CORS PoC and tricking real users into visiting it is a criminal act in every jurisdiction this course is taught in.
SECTION 23. Important Notes
Common beginner mistakes
- ●Confusing CORS with CSRF. CORS controls response READING; CSRF tricks the browser into SENDING state-changing requests.
- ●Believing CORS errors in DevTools mean a bug. Errors mean SOP is doing its job.
- ●Forgetting `credentials: 'include'` in PoCs.
- ●Testing only the homepage. Test every authenticated API endpoint.
- ●Reporting a CORS reflection without authenticated impact.
Pentester tips
- ●Test the six Origin variations on every endpoint.
- ●Use Burp Repeater to quickly swap Origin headers and diff responses.
- ●Map subdomains thoroughly. Many CORS bugs require chaining with subdomain takeover or XSS on a trusted host.
- ●Internal APIs are the highest-paying CORS targets when networks are large.
- ●When the bug is hard to exploit on its own, pivot via XSS on a trusted subdomain.
Bug bounty tips
- ●Critical reflected-origin + credentials regularly pays $5,000 to $25,000 on top programs.
- ●Always include a hosted PoC URL. Triagers love clickable demos.
- ●Show the full chain: Origin reflected -> credentials enabled -> sensitive data leaked.
- ●Use a clean, separate exploit domain. Do not host PoCs on shared infrastructure.
- ●Some programs accept `ACAO: *` on internal API as a separate finding.
Red team notes
- ●CORS abuse is silent. No alerts in most SIEMs.
- ●Combined with phishing, CORS gives full account access without password theft.
- ●Internal CORS via of-CORS-style typosquatting reaches deep into corporate networks.
- ●A compromised CDN node or DNS hijack of a trusted subdomain instantly weaponizes any CORS allowlist.
Defender tips
- ●Centralize CORS in middleware or a gateway; do not let individual endpoints set ACAO.
- ●Audit CORS at deploy time with automated tools (CORScanner, Corsy).
- ●Block insecure protocols in the allowlist.
- ●Use CSP alongside CORS as defense in depth.
- ●Never copy CORS code from a forum without review.
Real-world advice
- ●Many CORS bugs hide in mobile-only APIs that share the web API host.
- ●GraphQL endpoints are often misconfigured separately from REST.
- ●WebSocket endpoints rarely get CORS love and frequently allow any Origin (CSWSH).
- ●When a target has multiple subdomains, try every combination of regex bypasses.
Things to remember during exams
- ●CWE-942 = Permissive Cross-domain Policy.
- ●ACAO + ACAC: true with attacker origin = CRITICAL.
- ●Null Origin = sandboxed-iframe attack.
- ●SOP is the security; CORS is the relaxation.
- ●`ACAO: *` + `ACAC: true` is REJECTED by browsers.
Things to remember during real assessments
- ●Get explicit permission to host exploit pages and reach victim browsers.
- ●Throttle CORS scans. Mass scanning every subdomain looks like an attack.
- ●Demonstrate impact with a benign payload that only proves the bug.
- ●Save full HTTP traces (request + response with Origin and ACAO headers).
- ●Clean up: remove hosted PoCs after the report is accepted.
Frequently confused concepts
- ●CORS vs CSRF: CSRF tricks the browser into sending authenticated state-changing requests. CORS controls who can READ responses.
- ●CORS vs SOP: SOP is the wall. CORS is the door. Misconfigured CORS knocks the wall down.
- ●CORS vs cookies: cookies attach to cross-origin requests based on SameSite; CORS controls who reads the response.
- ●ACAO: * vs reflected ACAO: wildcard blocks credentials. Reflected matches credentials. Reflected is worse.
Interview tips
- ●Be ready to explain Same-Origin Policy without slides. Use the origin triple (scheme, host, port).
- ●Mention James Kettle's 2016 Bitcoin disclosure as the foundational research.
- ●Explain why `ACAO: *` plus `ACAC: true` is rejected by browsers (security baseline).
- ●Always finish with the defense: strict allowlist plus Vary: Origin.
Key takeaways
- ●CORS is not security. SOP is.
- ●Reflected Origin + Credentials = critical bug.
- ●Null Origin = sandboxed-iframe attack vector.
- ●Weak whitelists die to creative domain registration.
- ●The fix is one strict, exact allowlist. Always.
SECTION 24. Final Word from Your Instructor
You finished the CORS course. You now know more about this bug class than most working backend developers, and enough to find it, exploit it responsibly, and fix it in any codebase.
Here is the short version.
CORS misconfiguration works because developers confuse what CORS is. CORS is the consent protocol that lets a server selectively RELAX the Same-Origin Policy for specific trusted origins. SOP is the wall. CORS is the door. If the door is wired to open for anyone who claims to be the right origin, the wall does not exist. The browser is the enforcer; the server merely declares its policy via `Access-Control-Allow-Origin` and `Access-Control-Allow-Credentials`. Reflect Origin and set credentials true, and the browser cheerfully hands authenticated responses to whichever page claimed to be allowed.
The defense is one architectural rule. Hardcode a strict, exact allowlist of fully qualified origins (scheme + host + port). Never reflect the Origin header. Never trust `null`. Never use wildcard ACAO with credentials. Add `Vary: Origin` so CDNs cache per-origin. Set `SameSite=Strict` or `Lax` on session cookies as defense in depth. For GraphQL and WebSockets, write explicit policies; do not assume the REST-layer CORS config carries over.
On the offensive side, the workflow is short. Catalog authenticated endpoints. Swap the Origin in Burp Repeater. If ACAO reflects your value and ACAC is true, you have a credentialed CORS misconfig. Walk the six probe variations: reflection, null, http://, suffix-match, prefix-match, parsing quirks. Build the PoC. Deliver to a logged-in victim. Capture the response. Document with HTTP traces and a hosted PoC URL.
The disclosed reports prove this is current. James Kettle's 2016 Bitcoin exchange disclosure: API-key theft via reflected Origin, patched in 20 minutes. Truffle Security's of-CORS demonstrated internal-network CORS misconfigurations on Tesla and other corporate networks. Ayoub Safa's "Think Outside the Scope" continues to inform parsing-quirk bypasses in 2026. Google VRP rewards CORS reflections in 404 pages and error endpoints. Coinbase, VK.com, and other major platforms have all paid bounties for CORS bugs in the past few years.
When you see an HTTP response, look at the headers first. When you see `Access-Control-Allow-Origin`, ask where the value came from. When you see `Access-Control-Allow-Credentials: true`, ask whose data is behind this. When you see a wildcard, ask who is on this network. When you see a regex allowlist, ask how creative you can be with domain registration. If any answer raises an eyebrow, you have found a bug.
Stay curious. Stay ethical. Verify scope before you host any exploit page. The browser will obey almost anyone the server consents to; your job is to know when that consent was extended by accident.
Go hunt.