Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel AvanzadoPremium

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

Técnicas XS-Leaks 2026: timing attacks con performance.now(), error-based leaks via tag onerror/onload, frame-counting con CSP violations, ID-based leaks via element selector y storage timing.

Gorka El Bochi11 de mayo de 202616 min

Respuesta rápida

XS-Leaks son canales laterales que permiten leer información binaria o pequeña sobre una víctima logueada en otro origen — sin necesidad de XSS, sin sortear SOP directamente. Se basan en diferencias observables desde una página que solo embebe contenido cross-origin: tiempos de carga, errores de parseo, cantidad de frames, eventos disparados. Útiles para detectar si la víctima está logueada, si es admin, si tiene cierto rol, o filtrar IDs uno-bit por uno-bit.


El modelo de threat

El atacante:

  1. Hospeda attacker.com.
  2. La víctima visita atacante.com (phishing, ads, click-through).
  3. Atacante embebe / fetcha target.com cross-origin.
  4. Atacante observa side channels del browser para inferir datos.

Mitigaciones modernas: COOP, COEP, CORP, SameSite=Lax por defecto. Pero muchos endpoints siguen siendo leakables porque la mitigación se aplica a las páginas top-level, no al universo de subrecursos.


Canal 1 — Timing attacks con performance.now()

El más universal. Mide cuánto tarda un recurso cross-origin en cargar. Diferencias de 20-100ms suelen ser observables.

Setup básico

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)

Endpoints clásicos leakables por timing

EndpointDiferencia observable
Search con un término que existe vs uno que noTiempo de SQL query
/admin/dashboard vs /admin/non-existent200 vs 404
Email reset con email existente vs noEmail send delay
Endpoint con caché HIT vs MISSCaché latency
Endpoint con N rows (paginación)Render time

Anti-timing-detection: usa cache eviction

Si el browser cachea las responses, el segundo request es ~0ms. Para evitarlo:

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

Y mide múltiples veces para promediar jitter de red.


Canal 2 — Error-based leaks

Algunos recursos cross-origin disparan onerror / onload en <script>, <img>, <link> dependiendo del response. Aunque no puedes leer el contenido, puedes detectar si el response fue 200, 404, parseable o no.

Script tag onerror/onload differential

html
<script src="https://target.com/api/private/secret-id-12345"
        onload="known()" onerror="notFound()"></script>
  • Si el endpoint devuelve JS válido (200, content-type js) → onload.
  • Si devuelve 404 → onerror.
  • Si devuelve JSON inválido como JS → onerror.

Permite oracle: "¿existe el ID 12345 en el target para este usuario?"

Image dimensions leak

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

Si avatares de admin tienen tamaño distinto que regulares → leak.

CSS load differential

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

CSS dynamically generated por user state → ahora detectable.


Canal 3 — Frame counting

Hasta hace poco, window.length (número de iframes en una página) era leakable cross-origin si embebías la página. Mitigado en navegadores modernos via COOP, pero todavía funciona contra apps sin 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);

Variante con <object> o <iframe> + onload

Si el browser bloquea el load por X-Frame-Options: DENY, dispara onerror; si no, onload:

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

X-Frame-Options puede estar set condicionalmente por el server (algunas apps lo emiten solo para páginas protegidas) → leak directo de auth state.


Canal 4 — CSP violation reports (el premium)

CSP report endpoints son uno de los XS-Leaks más limpios y menos parcheados. Si el atacante hospeda una página con CSP que apunte el report-uri a su propio endpoint, cualquier violación CSP generada al cargar contenido cross-origin se reporta al atacante.

Sigue leyendo el chain completo

La parte que falta incluye el PoC paso a paso, código de explotación y la cadena completa que llevó al impacto. Disponible para suscriptores.

Practica esto en un lab

Xs Leaks Timing

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados