Skip to content

Instantly share code, notes, and snippets.

@darkxanter
Created October 26, 2020 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darkxanter/181ee613facea9e2b7e31635407faf1d to your computer and use it in GitHub Desktop.
Save darkxanter/181ee613facea9e2b7e31635407faf1d to your computer and use it in GitHub Desktop.
import { VueConstructor } from 'vue'
// Vue plugin for v-html-safe directive (safe alternative to insecure v-html)
const VueSafeHTML = {
install: function (vue: VueConstructor) {
const doc = document.implementation.createHTMLDocument('')
const div = doc.createElement('div')
function sanitizeHTML(htmlString: string) {
div.innerHTML = htmlString
const elements = div.querySelectorAll('*')
for (let i = elements.length - 1; i >= 0; i--) {
const element = elements[i]
// This is not needed because .innerHTML by default does not execute script tags
if (element.localName == 'script' && element.parentNode) {
element.parentNode.removeChild(element)
continue
}
if (!element.hasAttributes()) continue
const attributes = element.attributes
for (let j = attributes.length - 1; j >= 0; j--) {
const attribute = attributes[j]
// Remove insecure attributes starting "on*"" (e.g.: onload, onerror, ...) and also values starting "javascript:*" (e.g. href="javascript:alert(1)")
if (attribute.name.indexOf('on') == 0 || attribute.value.indexOf('javascript:') == 0)
element.removeAttribute(attribute.localName)
}
}
return div.innerHTML
}
vue.directive('html-safe', {
inserted: function (el, binding) {
el.innerHTML = sanitizeHTML(binding.value)
},
update: function (el, binding) {
if (binding.value !== binding.oldValue) el.innerHTML = sanitizeHTML(binding.value)
},
})
},
}
export default VueSafeHTML
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment