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

Stop reading about bugs and start hunting them

No card · free Academy · cancel anytime

Create free account

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

4,183

hunters training

68

labs from real hacks

2,125

completions

$14,790

paid out for these bugs

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

The community

This isn't a platform with users.It's people breaking the same things you are.

Inside people ask, share what they found and solve together what would block anyone on their own. It's free to join: no account, no plan, no email required.

Join the BBLABS community on Discord
Join the Discord

Free and open. You don't need a BBLABS account to join.