javascriptjsonelectronxsselectron-vue

Is <img :src="require`${JSON.parse(string)}`"> in electron vue is safe from XSS?


QUESTION UPDATED

I am inspecting a client's application written with Vue.js and I found there a following construction.

// Somewhere else in the code
var data = JSON.parse(jsonString); 

// In the vue component
<img :src="require(`@/assets/img/${data.someKey}.png`)">

jsonString is returned from a client's own server, however if the server is compromised then this data can be manipulated.

The application is running in electron environment.

Is this construction is safe to assume that data.someKey will always contain a safe data or there are some ways to abuse this construction and execute an XSS either though a require or through ${}?

The whole construction is very questionable and client's developers are convinced that JSON.parse is a sufficient protection in this case.

INITIAL QUESTION

I have a following construction in JS

var data = JSON.parse(jsonString); 

`${data.someKey}`

jsonString comes from an untrusted source.

Is this construction is safe to assume that data.someKey will always contain a safe data or there are some ways to abuse this construction and execute an XSS?


Solution

  • Unless you use your JSON data as raw HTML or an attribute, for example:

    element.innerHTML = `${data.someKey}`;
    

    or

    element.onclick = `${data.someKey}`;
    

    it's safe.

    Regading Vue, injecting raw HTML also dangerous:

    <script setup>
      const data = JSON.parse(`{"someKey": "<img onerror=alert('Wow!') src=X />" }`); 
    </script>
    
    <template>
      <div v-html="data.someKey"></div>
    </template>
    

    But regarding your example:

    <img :src="require(`@/assets/img/${data.someKey}.png`)">
    

    it's safe because Vue doesn't generate raw HTML but rather set attributes with DOM methods which is totally safe.

    You cannot bust a computed attribute in Vue, the value is escaped:

    <img data-v-e2be38e7="" alt="Vue logo" class="logo" src="x&quot; onerror=&quot;alert('busted')&quot;" width="125" height="125">