FlawOpen

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

Is Vue's v-html safe to use?

Reference page
Plain English

Vue's {{ comment }} interpolation is like displaying a quoted note behind glass: its angle brackets remain text. v-html asks the browser to open the note as HTML markup. If that markup is user-controlled, the browser may treat it as page structure or active content, creating an XSS risk.

VULNERABLE — raw user HTML
<p v-html="comment"></p>
// comment is parsed as real markup
HARDENED — sanitized rich HTML
<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 rich HTML before v-html

Prefer Vue's {{ }} interpolation when content is meant to be text. If a product feature truly needs user-authored rich HTML, sanitize it with a maintained library such as DOMPurify using a narrow allowlist, then bind only the sanitized result to v-html. Keep the sanitizer updated and test the allowed markup policy. Sanitization reduces risk but does not make arbitrary HTML universally safe; use a sandboxed iframe when content must remain untrusted and active. Vue does not compile v-html content as Vue templates.

Audit v-html and trace the data flow

Search every v-html binding. For each one, identify the source, the sanitizer and configuration, and every viewer who can see the rendered content. Flag direct user input, stored comments, CMS fields, and API responses; verify that ordinary text uses interpolation instead.

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

Common questions

Is this the same risk as React's dangerouslySetInnerHTML?

They both bypass the framework's ordinary text-escaping path and insert HTML into the DOM. Use a maintained sanitizer for necessary rich HTML, and do not treat sanitized output as universally safe.

References

See also Cross-Site Scripting (XSS, CWE-79): How It Works and How to Prevent It in Every Language — flawopen.com Is WKWebView loadHTMLString Safe for Untrusted Content? Reflected vs. Stored vs. DOM-Based XSS Android addJavascriptInterface Security Risks Angular XSS Protection: Safe Defaults and Bypass APIs Content-Type Sniffing XSS: MIME Types and nosniff CSP vs. Output Escaping: Do You Need Both?