Vue Safe HTML Directive
Vue Safe HTML is a Vue.js directive, currently at version 3.0.1, designed to dynamically render HTML content after programmatically stripping unwanted tags. It supports both Vue 2 and Vue 3, is TypeScript-ready, and has zero external dependencies, making it a lightweight solution for basic HTML sanitization. The library differentiates itself by offering explicit customization of allowed HTML tags and attributes, either globally during plugin installation or locally via directive modifiers. While it provides tag-stripping functionality, it explicitly states that it is not a comprehensive XSS (Cross-Site Scripting) protection mechanism and should not be relied upon for full security against malicious inputs. Releases appear to be event-driven, addressing bug fixes and compatibility, rather than following a strict time-based cadence. It also supports Nuxt SSR environments.
Common errors
-
My HTML attributes (like `href`, `class`, `style`) are disappearing after `v-safe-html` is applied!
cause Since version 2.2.0, `vue-safe-html` strips all HTML attributes by default for enhanced security. Only explicitly allowed attributes will be preserved.fixWhen installing the plugin, configure `allowedAttributes` with an array of attribute names you wish to retain: `Vue.use(VueSafeHTML, { allowedAttributes: ['href', 'class', 'title'] })`. -
I'm using `vue-safe-html` but still seeing XSS vulnerabilities in my application.
cause The library is a basic HTML tag-stripper and is explicitly stated as 'not XSS-safe'. It primarily focuses on whitelisting tags, not comprehensive XSS protection.fixDo not rely on `vue-safe-html` alone for XSS protection. Implement server-side sanitization, or use a dedicated, robust client-side XSS sanitization library (e.g., DOMPurify) as an additional layer of defense for untrusted HTML content. -
Certain HTML tags (e.g., `<img>`, `<span>`) are stripped even though I want them to render.
cause `vue-safe-html` operates on an `allowedTags` whitelist. By default, only a very limited set of common text formatting tags are allowed.fixExtend the default `allowedTags` array when installing the plugin: `import VueSafeHTML, { allowedTags } from 'vue-safe-html'; Vue.use(VueSafeHTML, { allowedTags: [...allowedTags, 'img', 'span'] })`. Alternatively, use directive modifiers for local overrides: `<div v-safe-html.img.span="myHtml"></div>`.
Warnings
- gotcha This library is explicitly NOT XSS-safe. It only strips tags programmatically based on a whitelist and does not provide comprehensive protection against all forms of Cross-Site Scripting attacks. Do not rely on it as a sole security measure for untrusted HTML.
- breaking Starting from version 2.2.0, HTML attributes are *completely removed* by default. If you were relying on attributes like `href`, `class`, or `src` to be preserved, they will now be stripped unless explicitly allowed.
- breaking The regex for sanitizing HTML tags was rewritten in v2.2.0, addressing several issues where input tags or tags starting with certain characters were not stripped correctly. While this improves security, it might alter behavior for previously malformed or unexpectedly allowed tags.
- gotcha If you provide an empty array to the `allowedTags` option (e.g., `Vue.use(VueSafeHTML, { allowedTags: [] })`), all HTML tags will be stripped from the content, leaving only plain text.
Install
-
npm install vue-safe-html -
yarn add vue-safe-html -
pnpm add vue-safe-html
Imports
- VueSafeHTML
const VueSafeHTML = require('vue-safe-html');import VueSafeHTML from 'vue-safe-html';
- allowedTags
import VueSafeHTML, { allowedTags } from 'vue-safe-html'; - v-safe-html
<div v-safe-html="myHtmlContent"></div>
Quickstart
import Vue from 'vue';
import VueSafeHTML from 'vue-safe-html';
// Optionally configure global allowed tags or attributes
Vue.use(VueSafeHTML, {
allowedTags: ['p', 'strong', 'em', 'a'],
allowedAttributes: ['href', 'title']
});
new Vue({
el: '#app',
data: {
unsafeHtml: '<script>alert("XSS attempt!")</script><b>Hello</b> <a href="malicious.com" onclick="doEvil()">World</a> <p>This is safe.</p>'
},
template: `
<div id="app">
<h3>Content with default sanitization:</h3>
<div v-safe-html="unsafeHtml"></div>
<h3>Content with local override (only allowing 'p'):</h3>
<div v-safe-html.p="unsafeHtml"></div>
</div>
`
});