Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

fme's avatar
Level 1

XSS injection through Vue + Blade interaction

Context. I use Laravel Blade templates to write good old server-side rendered multiple-pages applications. From time to time, if a specific page requires more user-friendly interactions, I sprinkle a few Vue components in it. I use the approach which was quite common a few years ago, for example described in the "Building a flash message component with Vue.js and Tailwind CSS" tutorial where the main Blade template is something like

<div id="app">
    <flash-message></flash-message>
</div>

and the Vue application is mounted on the app HTML element in order to be able to render sparkled components such as the flash-message one here.

XSS injection. Now issues arise when the Blade template renders user-input content (imagine that there is a form for users to modify the project's name), for example

<div id="app">
	<b>Project name:</b> {{ $project->name }}
    <flash-message></flash-message>
</div>

Notice that here, I correctly use {{ $project->name }} to prevent (from Blade's point of view) rendering say raw HTML input by the user. But, if the user has input very nasty data as the project name, for example, the string {{ _c.constructor("alert(1)")() }}, then this string is rendered as is by Blade's escaping engine (which sees no HTML reason to escape it). And in fact, everything would be fine if I was not using Vue on top of it.

From Vue's perspective, this string which has been rendered by Blade must now be interpreted as a JavaScript command, and it is executed. Of course, the issue is ubiquitous in my application since the <div id="app"> HTML tag is at the very top, and the large web pages are full of Blade-escaped user-input strings, which are thus re-parsed by Vue.

Questions: Is the practice of using "a few Vue components" inside a mostly PHP-Blade traditional application still used? If so, how do people protect themselves from such XSS injections? I could maybe write a Middleware to "clean" user input strings say from the {{ or }} characters, but I feel like writing such code myself is error-prone as I would always be forgetting some clever way an attacker might find to exploit the "double layer of parsing" done by Blade then Vue. I am eager to read your thoughts on this issue.

Many thanks,

0 likes
1 reply
fme's avatar
Level 1

In case someone has the same problem, here are the two solutions I found:

  • Use Vue's v-pre directive to protect each portion of the HTML where Blade could inject user input containing curly braces. For example, a safe version of the above vulnerable template would be
<div id="app">
	<b>Project name:</b> <span v-pre>{{ $project->name }}</span>
    <flash-message></flash-message>
</div>
  • Disable entirely template interpolation using Vue's compiler options. Templates located inside Vue components are still correctly parsed, so this allows to sparkle Vue components inside a largely Blade-HTML application. This has to be done before mounting the Vue application, e.g.
import { createApp } from 'vue'
const app = createApp({})
app.config.compilerOptions.delimiters = ['', ''];
app.mount('#app');

The second option is more systematic (there is no need to protect exhaustively all places where user input is rendered), but might have some interactions which I don't know about with other things.

1 like

Please or to participate in this conversation.