Vuejs: V-HTML data binding of html data against eslint rule

Viewed 13441

I am using the following method to bind html and display in my page. It is working perfectly, however i receive a warning from my eslint that 'v-html' directive can lead to XSS attack.eslint(vue/no-v-html)

  <button
        id="foreignerBtn"
        class="tabButton"
        @click="foreignerClick"
        v-html="textContent2"
      ></button>

Then i change it following method. But i not able to render html tag.

 <button
            id="foreignerBtn"
            class="tabButton"
            @click="foreignerClick"
          >{{ textContent2 }}</button>
4 Answers

As Decade Moon mentions you can disable the rule if the content passed to v-html is sanitized HTML.

https://eslint.vuejs.org/rules/no-v-html.html

Disable the rule by wrapping the html in

<!-- eslint-disable vue/no-v-html -->
<button
        id="foreignerBtn"
        class="tabButton"
        @click="foreignerClick"
        v-html="textContent2"
      ></button>
<!--eslint-enable-->

As stated in the other answer, you can disable the warning but a good practice is to make sure the rule is rightfully disabled.

To do so, you can use dompurify that will parse the HTML you are giving to the browser, remove any malicious part and display it safely.

The issue is still there but you can use RisXSS which is an ESLint plugin that will warn the uses of v-html if you do not sanitize it before (in a sense, this is an improved version of vue/no-v-html ESLint rule).

To do so, install dompurify and eslint-plugin-risxss:

npm install dompurify eslint-plugin-risxss

Add risxss to your ESLint plugins then use DOMPurify:

<template>
    <button
        id="foreignerBtn"
        class="tabButton"
        @click="foreignerClick"
        v-html="sanitizedTextContent2"
        <!-- no warning, good to go -->
    ></button>
    <button
        id="foreignerBtn"
        class="tabButton"
        @click="foreignerClick"
        v-html="textContent2"
        <!-- warning here -->
    ></button>
</template>
<script>
import DOMPurify from 'dompurify';

export default {
    data () {
    return {
        sanitizedTextContent2: DOMPurify.sanitize(textContent2)
    }
    }
}
</script>

Disclaimer: I am a contributor of RisXSS plugin.

You can wrap the code in

<!-- eslint-disable -->
<button
  id="foreignerBtn"
  class="tabButton"
  @click="foreignerClick"
  v-html="textContent2"
></button>
<!-- eslint-enable -->

It will hide all the eslint warnings including v-html

Following the answer of clementescolano, I came up with the following solution, using a custom directive:

in your main.js (or wherever you define your vue instance), add:

import DOMPurify from "dompurify";

// ...

Vue.directive("sane-html", (el, binding) => {
  el.innerHTML = DOMPurify.sanitize(binding.value);
});

Now, wherever you were using the directive v-html, use v-sane-html in stead.

N.b. see here for vue2 custom directives

Related