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:
- Hospeda
attacker.com. - La víctima visita atacante.com (phishing, ads, click-through).
- Atacante embebe / fetcha
target.comcross-origin. - 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
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
| Endpoint | Diferencia observable |
|---|---|
| Search con un término que existe vs uno que no | Tiempo de SQL query |
/admin/dashboard vs /admin/non-existent | 200 vs 404 |
| Email reset con email existente vs no | Email send delay |
| Endpoint con caché HIT vs MISS | Caché 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:
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, sí puedes detectar si el response fue 200, 404, parseable o no.
Script tag onerror/onload differential
<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
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
<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.
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:
<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
Sigue aprendiendo · cuenta gratis
Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.