Nivel AvanzadoPremium

Secondary context XSS — encontrando XSS donde el primary parsing no lo detecta

Cuando el primary parsing escapa pero un secondary context (markdown render, BBCode, custom template engine) interpreta de nuevo, abriendo XSS oculto a sanitizers tradicionales.

Gorka El Bochi11 de mayo de 202615 min

Deja de leer sobre bugs y empieza a cazarlos

Sin tarjeta · Academy gratis · cancela cuando quieras

Crear cuenta gratis

Respuesta rápida

Secondary context XSS surge cuando el input pasa por dos pipelines de parsing: el primero escapa lo que entiende como peligroso, el segundo re-interpreta lo que el primero ignoró. Markdown renderers, BBCode parsers, custom template engines, latex-to-HTML, SVG inline serialization — todos son secondary contexts donde los caracteres "seguros" del primary se convierten en payloads. El truco: encontrar el delta entre lo que el sanitizer mira y lo que el render finalmente emite.


El modelo de threat

Pipeline típico vulnerable:

css
User input
    ↓
[Primary parser]   ← escapa <, >, " según context HTML
    ↓
[Secondary parser] ← markdown / BBCode / template engine → emite NUEVO HTML
    ↓
DOM render        ← ejecuta el HTML resultante

El sanitizer suele aplicarse en el primary o en el output final. Si solo aplica en el primary, el secondary tiene libertad para emitir lo que quiera. Si aplica en el output final, el sanitizer está protegido — pero solo si conoce todos los outputs posibles del secondary.


Markdown — el secondary context #1

Markdown→HTML es el caso más explotado. CommonMark/markdown-it/marked/showdown todos tienen comportamientos diferentes en edge cases.

markdown
[click me](javascript:alert(1))

Algunos parsers emiten:

html
<a href="javascript:alert(1)">click me</a>

Solución típica: parser bloquea javascript:. Pero:

markdown
[click me](javascript&#58;alert(1))
[click me](javascript&#x3a;alert(1))
[click me](java&#9;script:alert(1))
[click me](java%0ascript:alert(1))

CommonMark spec dice "preserve the URL as-is, decode HTML entities at render time". Algunos parsers decodan, otros no. La inconsistencia es el bypass.

Vector — HTML raw inline

Por defecto la mayoría de parsers permiten HTML raw mezclado con markdown:

markdown
Hola

<img src=x onerror=alert(1)>

mundo

Mitigación común: pasar el output por DOMPurify. Pero DOMPurify trabaja en el HTML final, no en markdown. Si el parser emite HTML válido que DOMPurify acepta + un side effect, el chain pasa.

markdown
[click][autolink]

[autolink]: javascript:alert(1)

Reference-style links. El parser puede decodar el destino later, después del sanitize.

Vector — code blocks que escapan al render

Markdown permite lang hint en code blocks. Un payload típico es un bloque "html" con un payload dentro:

css
```html
<img src=x onerror=alert(1)>
```

Si el renderer pasa el code block through un syntax highlighter (Prism, highlight.js, Shiki) que emite HTML "structured", el sanitizer del output puede asumir que está dentro de <pre><code> y permitir tags... y algunos highlighters serializan mal.

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.

Gratis · sin cuenta

La checklist que repaso en cada objetivo nuevo

47 comprobaciones ordenadas por coste: primero lo que te puede meter en un lío, luego lo barato, y al final lo caro — que es donde están los bounties grandes. Te la mando al correo ahora mismo.

Te das de baja en un clic, desde cualquier correo.

Practica esto en un lab

Secondary Context

Resolver

Sigue aprendiendo · cuenta gratis

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

Crear cuenta

Artículos relacionados

2.786

hunters entrenando

63

labs de hackeos reales

1.767

completaciones

$14.790

pagados por estos bugs

37 flags capturadas esta semana·Hackeos reales de HackerOne · YesWeHack · Bugcrowd·Sin permanencia·Academy gratis

La comunidad

Esto no es una plataforma con usuarios.Es gente rompiendo lo mismo que tú.

Dentro se pregunta, se enseña lo que se ha encontrado y se resuelve en grupo lo que atascaría a cualquiera solo. Se entra gratis: sin cuenta, sin plan y sin dejar el correo.

Entrar a la comunidad de BBLABS en Discord
Entrar al Discord

Es gratis y abierto. No hace falta tener cuenta en BBLABS para entrar.