За замовчуванням Vue екранує дані: інтерполяція {{ }} і прив'язки атрибутів вставляють значення як текст, а не як HTML.
<p>{{ comment.body }}</p> <!-- <script> покажеться як текст -->
<a :title="comment.author">...</a> <!-- значення атрибута екрановано -->
Де захист закінчується:
1. v-html вставляє рядок як HTML:
<div v-html="comment.body"></div> <!-- XSS, якщо body від користувача -->
Для контенту від користувачів - лише після санітизації (DOMPurify на клієнті чи HTML Purifier на сервері), а краще - зберігати Markdown і рендерити безпечним рендерером з білим списком тегів.
2. URL у атрибутах: екранування не захищає від схеми javascript::
<a :href="user.website">Сайт</a> <!-- javascript:alert(1) виконається при кліку -->
Перевіряйте протокол (http:/https:) перед виведенням посилань з даних користувача.
3. :style з даних користувача - можливі атаки через CSS (підміна інтерфейсу, витік через url()).
4. Шаблон з даних користувача. Найнебезпечніший випадок - компіляція рядка, що містить ввід користувача, як шаблону Vue:
createApp({ template: `<div>${userInput}</div>` }); // виконання довільних виразів
Шаблон Vue - це код. Будь-що, що компілюється як шаблон, має повністю контролюватися розробником.
5. Серверний рендер + Vue в браузері (Blade, Laravel). Якщо Vue монтується на розмітку, яку сервер згенерував з даними користувача (in-DOM шаблон), то {{ }} у даних користувача Vue виконає як вираз. Користувач пише коментар {{ constructor.constructor('alert(1)')() }} - Blade екранує HTML, але не фігурні дужки, і Vue їх обчислить. Захист: не монтувати Vue на області з користувацьким вмістом, позначати такі ділянки v-pre, передавати дані через props/JSON, а не через розмітку.
Вирази шаблонів у «пісочниці»: у шаблоні доступний лише обмежений набір глобальних об'єктів (Math, Date тощо), а не window. Але це не межа безпеки - через ланцюжок конструкторів можна дістатися до Function, тому вимога «шаблони лише від розробника» лишається.
Що ще: Content Security Policy знижує наслідки XSS. Повна збірка Vue з компілятором шаблонів у браузері потребує unsafe-eval; збірка лише з runtime (шаблони скомпільовані Vite) - ні.