- The Vue Instance
- Template Syntax
- Computed Properties and Watchers
- Class and Style Bindings
- Conditional Rendering
- List Rendering
- Event Handling
- Form Input Bindings
- Components Basics
- Component Registration
- Custom Events
- Dynamic & Async Components
- Handling Edge Cases
Transitions & Animation
- Enter/Leave & List Transitions
- State Transitions
Reusability & Composition
- Custom Directives
- Render Functions & JSX
- Single File Components
- TypeScript Support
- Production Deployment
- State Management
- Server-Side Rendering
- Reactivity in Depth
- Migration from Vue 1.x
- Migration from Vue Router 0.7.x
- Migration from Vuex 0.6.x to 1.0
- Migration to Vue 2.7
- Comparison with Other Frameworks
- Join the Vue.js Community!
- Meet the Team
You’re browsing the documentation for v2.x and earlier. For v3.x, click here.
When a vulnerability is reported, it immediately becomes our top concern, with a full-time contributor dropping everything to work on it. To report a vulnerability, please email email@example.com.
While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
Whether using templates or render functions, content is automatically escaped. That means in this template:
then it would be escaped to the following HTML:
thus preventing the script injection. This escaping is done using native browser APIs, like
textContent, so a vulnerability can only exist if the browser itself is vulnerable.
Similarly, dynamic attribute bindings are also automatically escaped. That means in this template:
then it would be escaped to the following HTML:
thus preventing the close of the
title attribute to inject new, arbitrary HTML. This escaping is done using native browser APIs, like
setAttribute, so a vulnerability can only exist if the browser itself is vulnerable.
For example, services like CodePen and JSFiddle allow user-provided content to be executed, but it’s in a context where this is expected and sandboxed to some extent inside iframes. In the cases when an important feature inherently requires some level of vulnerability, it’s up to your team to weigh the importance of the feature against the worst-case scenarios the vulnerability enables.
As you learned earlier, Vue automatically escapes HTML content, preventing you from accidentally injecting executable HTML into your application. However, in cases where you know the HTML is safe, you can explicitly render HTML content:
Using a template:
Using a render function:
Using a render function with JSX:
Note that user-provided HTML can never be considered 100% safe unless it’s in a sandboxed iframe or in a part of the app where only the user who wrote that HTML can ever be exposed to it. Additionally, allowing users to write their own Vue templates brings similar dangers.
In a URL like this:
If you’re ever doing URL sanitization on the frontend, you already have a security issue. User-provided URLs should always be sanitized by your backend before even being saved to a database. Then the problem is avoided for every client connecting to your API, including native mobile apps. Also note that even with sanitized URLs, Vue cannot help you guarantee that they lead to safe destinations.
Looking at this example:
let’s assume that
userProvidedStyles, malicious users could still provide CSS to “click jack”, e.g. styling the link into a transparent box over the “Log in” button. Then if
https://user-controlled-website.com/ is built to resemble the login page of your application, they might have just captured a user’s real login information.
You may be able to imagine how allowing user-provided content for a
<style> element would create an even greater vulnerability, giving that user full control over how to style the entire page. That’s why Vue prevents rendering of style tags inside templates, such as:
To keep your users fully safe from click jacking, we recommend only allowing full control over CSS inside a sandboxed iframe. Alternatively, when providing user control through a style binding, we recommend using its object syntax and only allowing users to provide values for specific properties it’s safe for them to control, like this:
We strongly discourage ever rendering a
Sometimes we receive vulnerability reports on how it’s possible to do cross-site scripting (XSS) in Vue templates. In general, we do not consider such cases to be actual vulnerabilities, because there’s no practical way to protect developers from the two scenarios that would allow XSS:
The developer is explicitly asking Vue to render user-provided, unsanitized content as Vue templates. This is inherently unsafe and there’s no way for Vue to know the origin.
The developer is mounting Vue to an entire HTML page which happens to contain server-rendered and user-provided content. This is fundamentally the same problem as #1, but sometimes devs may do it without realizing. This can lead to possible vulnerabilities where the attacker provides HTML which is safe as plain HTML but unsafe as a Vue template. The best practice is to never mount Vue on nodes that may contain server-rendered and user-provided content.
Beyond the recommendations made above for Potential Dangers, we also recommend familiarizing yourself with these resources:
Then use what you learn to also review the source code of your dependencies for potentially dangerous patterns, if any of them include 3rd-party components or otherwise influence what’s rendered to the DOM.
HTTP security vulnerabilities, such as cross-site request forgery (CSRF/XSRF) and cross-site script inclusion (XSSI), are primarily addressed on the backend, so aren’t a concern of Vue’s. However, it’s still a good idea to communicate with your backend team to learn how to best interact with their API, e.g. by submitting CSRF tokens with form submissions.
There are some additional security concerns when using SSR, so make sure to follow the best practices outlined throughout our SSR documentation to avoid vulnerabilities.