FlawOpen

flawopen.com/XSS en JavaScript/Vue v-html

Riesgo de XSS con Vue v-html

Página de referencia
En palabras sencillas

La interpolación {{ comment }} de Vue es como mostrar una nota entre comillas tras un cristal: los signos angulares siguen siendo texto. v-html pide al navegador que abra la nota como HTML. Si el marcado lo controla un usuario, el navegador puede tratarlo como estructura o contenido activo y crear un riesgo de XSS.

VULNERABLE — HTML sin procesar del usuario
<p v-html="comment"></p>
// comment se interpreta como marcado real
CORREGIDO — HTML enriquecido saneado
<script setup>
import { computed } from 'vue'
import DOMPurify from 'dompurify'

const props = defineProps({ comment: String })
const safeComment = computed(() =>
  DOMPurify.sanitize(props.comment ?? '', {
    ALLOWED_TAGS: ['p', 'strong', 'em'],
    ALLOWED_ATTR: []
  })
)
</script>

<template>
  <div v-html="safeComment"></div>
</template>

Sanear HTML enriquecido antes de v-html

Prefiere la interpolación {{ }} de Vue cuando el contenido debe ser texto. Si una función necesita HTML enriquecido escrito por usuarios, pásalo por un sanitizador mantenido, como DOMPurify, con una lista de permitidos reducida; vincula a v-html solo el resultado saneado. Mantén el sanitizador actualizado y prueba la política de marcado permitido. Sanear reduce el riesgo, pero no hace que cualquier HTML sea seguro en todos los contextos; usa un iframe aislado cuando el contenido deba seguir siendo no confiable y activo. Vue no compila el contenido de v-html como plantillas Vue.

Auditar v-html y rastrear el flujo de datos

Busca todas las vinculaciones v-html. Para cada una, identifica el origen, el sanitizador y su configuración, y quién puede ver el contenido renderizado. Marca entradas directas del usuario, comentarios almacenados, campos de CMS y respuestas de API; confirma que el texto normal usa interpolación.

grep -rn "v-html" --include="*.vue" .

Preguntas frecuentes

¿Es el mismo riesgo que dangerouslySetInnerHTML de React?

Ambos omiten la vía normal de escape de texto del framework e insertan HTML en el DOM. Usa un sanitizador mantenido cuando el HTML enriquecido sea imprescindible y no consideres universalmente seguro el resultado saneado.

Referencias

Véase también Cross-Site Scripting (XSS, CWE-79): cómo funciona y cómo evitarlo en cada lenguaje — flawopen.com WKWebView: ¿HTML no confiable seguro? XSS reflejado, almacenado y basado en DOM: ¿en qué se diferencian? Riesgos de seguridad de addJavascriptInterface en Android Protección XSS de Angular: valores seguros y APIs de omisión XSS por MIME sniffing: Content-Type y nosniff CSP y escape de salida: ¿necesitas ambos?