Not by itself, but it removes Vue's protection for that element. Vue escapes normal text and attribute bindings. v-html tells Vue to insert raw HTML, so any user-controlled string becomes a possible XSS path. Use it only for trusted or sanitized content, and review every occurrence.
What Vue escapes and what v-html skips
The Vue security guide explains that content is automatically escaped, whether you use templates or render functions. If a variable contains a script tag, the browser shows it as text. The same applies to dynamic attribute bindings. Vue does this with native browser APIs such as textContent and setAttribute, so a flaw can only exist if the browser itself is vulnerable.
The v-html directive, or the innerHTML prop in a render function, switches that off on purpose. The guide's warning is direct: user-provided HTML can never be considered 100 percent safe unless it sits in a sandboxed iframe, or in a part of the app where only the user who wrote it can ever see it.
When it is acceptable
| Content source | Reasonable? | Why |
|---|---|---|
| Static HTML your team wrote and ships in the bundle | Yes | No attacker influence |
| HTML from your CMS, edited by staff | Maybe | Depends on who can edit and how the CMS cleans input |
| Markdown rendered to HTML from users | Only after sanitizing | Rendered output can still carry active markup |
| Comments, profiles, chat messages | Avoid | Directly attacker controlled |
| HTML from a third party API | Sanitize first | You do not control that source |
If you must render HTML that someone else can influence, run it through a maintained sanitizer before it reaches v-html, and do not modify it afterwards. A sanitizer is a second line of defense, not permission to stop thinking about the source.
How to review a Vue project
- Search for v-html and for innerHTML in render functions and JSX.
- Write down the origin of each value, from the database column or API field to the component prop.
- Mark each one trusted, sanitized or unknown. Fix the unknown ones first.
- Turn on the eslint-plugin-vue rule vue/no-v-html. It reports every use of the directive, includes an ignorePattern option for variables you have vetted, and is part of the plugin's recommended presets. The plugin's own text notes you can switch it off if you are certain the content is sanitized HTML.
- Check third party components too. The Vue guide recommends reviewing the source of dependencies that influence what is rendered to the DOM.
A related trap: where Vue is mounted
The Vue team says it does not treat most template XSS reports as framework vulnerabilities, because two situations cannot be protected. One is when a developer asks Vue to render unsanitized user content as a template. The other is mounting Vue on a page that already contains server-rendered, user-provided content. Attacker HTML that is harmless as plain HTML can be dangerous when Vue compiles it as a template. The guide's advice is never to mount Vue on nodes that may contain such content.
Try it yourself
Click through it at your own pace, or open it full screen. Watch how a static code scan reports a risky call with its file and line, the same shape as a v-html review list.
Safeguard offers a free scan at gold.safeguard.sh/scan that checks the dependencies in a project, including the UI libraries that render HTML for you.
Quick check
Is v-html always an XSS bug?
No. It is safe when the HTML is fully trusted. It becomes a bug when an attacker can influence the string and nothing sanitizes it.
Does a lint rule fix the problem?
It finds the uses. You still decide for each one whether the source is trusted or needs sanitizing.
Sources
- Vue security guide
- eslint-plugin-vue no-v-html rule
- OWASP JavaScript and TypeScript Security Cheat Sheet
Last reviewed: 19 October 2026.