mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
155 lines
4.5 KiB
Markdown
155 lines
4.5 KiB
Markdown
# Vue.js
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## XSS Sinks in Vue.js
|
||
|
||
### v-html Directive
|
||
The `v-html` directive renders **raw** HTML, so any `<script>` (or an attribute like `onerror`) embedded in unsanitised user input executes immediately.
|
||
|
||
```html
|
||
<div id="app">
|
||
<div v-html="htmlContent"></div>
|
||
</div>
|
||
<script>
|
||
new Vue({
|
||
el: '#app',
|
||
data: {
|
||
htmlContent: '<img src=x onerror=alert(1)>'
|
||
}
|
||
})
|
||
</script>
|
||
```
|
||
|
||
### v-bind with src or href
|
||
Binding a user string to URL-bearing attributes (`href`, `src`, `xlink:href`, `formaction` …) lets payloads such as `javascript:alert(1)` run when the link is followed.
|
||
|
||
```html
|
||
<div id="app">
|
||
<a v-bind:href="userInput">Click me</a>
|
||
</div>
|
||
<script>
|
||
new Vue({
|
||
el: '#app',
|
||
data: {
|
||
userInput: 'javascript:alert(1)'
|
||
}
|
||
})
|
||
</script>
|
||
```
|
||
|
||
### v-on with user-controlled handlers
|
||
`v-on` compiles its value with `new Function`; if that value comes from the user, you hand them code-execution on a plate.
|
||
|
||
```html
|
||
<div id="app">
|
||
<button v-on:click="malicious">Click me</button>
|
||
</div>
|
||
<script>
|
||
new Vue({
|
||
el: '#app',
|
||
data: { malicious: 'alert(1)' }
|
||
})
|
||
</script>
|
||
```
|
||
|
||
### Dynamic attribute / event names
|
||
User-supplied names in `v-bind:[attr]` or `v-on:[event]` let attackers create any attribute or event handler, bypassing static analysis and many CSP rules.
|
||
|
||
```html
|
||
<img v-bind:[userAttr]="payload">
|
||
<!-- userAttr = 'onerror', payload = 'alert(1)' -->
|
||
```
|
||
|
||
### Dynamic component (`<component :is>`)
|
||
Allowing user strings in `:is` can mount arbitrary components or inline templates—dangerous in the browser and catastrophic in SSR.
|
||
|
||
```html
|
||
<component :is="userChoice"></component>
|
||
<!-- userChoice = '<script>alert(1)</script>' -->
|
||
```
|
||
|
||
### Untrusted templates in SSR
|
||
During server-side rendering, the template runs **on your server**; injecting user HTML can escalate XSS to full Remote Code Execution (RCE). CVEs in `vue-template-compiler` prove the risk.
|
||
|
||
```js
|
||
// DANGER – never do this
|
||
const app = createSSRApp({ template: userProvidedHtml })
|
||
```
|
||
|
||
### Filters / render functions that eval
|
||
Legacy filters that build render strings or call `eval`/`new Function` on user data are another XSS vector—replace them with computed properties.
|
||
|
||
```js
|
||
Vue.filter('run', code => eval(code)) // DANGER
|
||
```
|
||
|
||
---
|
||
|
||
## Other Common Vulnerabilities in Vue Projects
|
||
|
||
### Prototype pollution in plugins
|
||
Deep-merge helpers in some plugins (e.g., **vue-i18n**) have allowed attackers to write to `Object.prototype`.
|
||
|
||
```js
|
||
import merge from 'deepmerge'
|
||
merge({}, JSON.parse('{ "__proto__": { "polluted": true } }'))
|
||
```
|
||
|
||
### Open redirects with vue-router
|
||
Passing unchecked user URLs to `router.push` or `<router-link>` can redirect to `javascript:` URIs or phishing domains.
|
||
|
||
```js
|
||
this.$router.push(this.$route.query.next) // DANGER
|
||
```
|
||
|
||
### CSRF in Axios / fetch
|
||
SPAs still need server-side CSRF tokens; SameSite cookies alone can’t block auto-submitted cross-origin POSTs.
|
||
|
||
```js
|
||
axios.post('/api/transfer', data, {
|
||
headers: { 'X-CSRF-TOKEN': token }
|
||
})
|
||
```
|
||
|
||
### Click-jacking
|
||
Vue apps are frameable unless you send both `X-Frame-Options: DENY` and `Content-Security-Policy: frame-ancestors 'none'`.
|
||
|
||
```http
|
||
X-Frame-Options: DENY
|
||
Content-Security-Policy: frame-ancestors 'none';
|
||
```
|
||
|
||
### Content-Security-Policy pitfalls
|
||
The full Vue build needs `unsafe-eval`; switch to the runtime build or pre-compiled templates so you can drop that dangerous source.
|
||
|
||
```http
|
||
Content-Security-Policy: default-src 'self'; script-src 'self';
|
||
```
|
||
|
||
### Supply-chain attacks (node-ipc – March 2022)
|
||
The sabotage of **node-ipc**—pulled by Vue CLI—showed how a transitive dependency can run arbitrary code on dev machines. Pin versions and audit often.
|
||
|
||
```shell
|
||
npm ci --ignore-scripts # safer install
|
||
```
|
||
|
||
---
|
||
|
||
## Hardening Checklist
|
||
|
||
1. **Sanitise** every string before it hits `v-html` (DOMPurify).
|
||
2. **Whitelist** allowed schemes, attributes, components, and events.
|
||
3. **Avoid `eval`** and dynamic templates altogether.
|
||
4. **Patch dependencies weekly** and monitor advisories.
|
||
5. **Send strong HTTP headers** (CSP, HSTS, XFO, CSRF).
|
||
6. **Lock your supply chain** with audits, lockfiles, and signed commits.
|
||
|
||
## References
|
||
|
||
- [https://www.stackhawk.com/blog/vue-xss-guide-examples-and-prevention/](https://www.stackhawk.com/blog/vue-xss-guide-examples-and-prevention/)
|
||
- [https://medium.com/@isaacwangethi30/vue-js-security-6e246a7613da](https://medium.com/@isaacwangethi30/vue-js-security-6e246a7613da)
|
||
- [https://vuejs.org/guide/best-practices/security](https://vuejs.org/guide/best-practices/security)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|