FlawOpen

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

Risco de XSS no Vue v-html

Página de referência
Em linguagem simples

A interpolação {{ comment }} do Vue é como exibir um bilhete entre aspas atrás de um vidro: os sinais de menor e maior continuam sendo texto. v-html pede ao navegador que interprete o bilhete como HTML. Se a marcação vier do usuário, o navegador poderá tratá-la como estrutura da página ou conteúdo ativo, criando risco de XSS.

VULNERÁVEL — HTML bruto do usuário
<p v-html="comment"></p>
// comment é interpretado como marcação real
CORRIGIDO — HTML rico sanitizado
<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>

Sanitize HTML rico antes de usar v-html

Prefira a interpolação {{ }} do Vue quando o conteúdo deve ser texto. Se um recurso realmente precisar de HTML rico escrito por usuários, sanitize-o com uma biblioteca mantida, como DOMPurify, usando uma allowlist restrita; vincule a v-html somente o resultado sanitizado. Mantenha o sanitizador atualizado e teste a política de marcação permitida. A sanitização reduz o risco, mas não torna qualquer HTML universalmente seguro; use um iframe isolado quando o conteúdo precisar continuar não confiável e ativo. Vue não compila o conteúdo de v-html como templates Vue.

Audite v-html e rastreie o fluxo dos dados

Pesquise todas as vinculações v-html. Para cada uma, identifique a origem, o sanitizador e sua configuração, e quem pode ver o conteúdo renderizado. Marque entrada direta do usuário, comentários armazenados, campos de CMS e respostas de API; confirme que texto comum usa interpolação.

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

Perguntas comuns

Isso tem o mesmo risco que dangerouslySetInnerHTML do React?

Ambos ignoram o caminho normal de escape de texto do framework e inserem HTML no DOM. Use um sanitizador mantido quando HTML rico for realmente necessário, e não trate a saída sanitizada como universalmente segura.

Referências

Veja também Cross-Site Scripting (XSS, CWE-79): como funciona e como evitar em todas as linguagens — flawopen.com WKWebView: HTML não confiável é seguro? XSS refletido, armazenado e baseado em DOM: quais são as diferenças? Riscos de segurança do addJavascriptInterface no Android Proteção XSS do Angular: padrões seguros e APIs de bypass XSS por MIME sniffing: Content-Type e nosniff CSP e escape de saída: você precisa dos dois?