# Vue I18n: escapeParameter does not prevent XSS through srcdoc in translation messages

Vue I18n's escapeParameter sanitizer escapes markup into character references, but inside iframe srcdoc the browser decodes them, yielding same-origin DOM XSS.

- Payout: Research
- Severity: high
- Program: Vue I18n
- Found by: lissy93, NotAFlightRisk
- Disclosed: 2026-10-28
- CVE: CVE-2026-118257
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-83rm-6c8r-g728
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-83rm-6c8r-g728
- Tags: area:web domain:web impact:integrity kind:research platform:ghsa sev:high tech:nodejs technique:chained technique:incomplete-fix technique:source-review vuln:xss

**Target:** vue-i18n translation rendering via v-html (sanitizeTranslatedHtml)
**Root cause:** sanitizeTranslatedHtml neutralizes markup and event handlers only by emitting character references, which the browser decodes before parsing srcdoc as a nested same-origin document.
**Steps:**
1. Enable escapeParameter: true and render translations with v-html.
2. Use message `<iframe srcdoc="<b>x</b>"></iframe>` (or place an untrusted parameter inside srcdoc).
3. Call `i18n.global.t('message')`; output is `<iframe srcdoc="&lt;b&gt;x&lt;/b&gt;"></iframe>`.
4. Browser decodes the srcdoc value and parses it as a same-origin document; any markup/script there executes.
**How found:** Reviewed the sanitizer added for CVE-2025-53892 and noticed its escaping/neutralization relies on character references, which are re-decoded inside srcdoc; tested a message containing an iframe srcdoc.
**Exploitation:** Attacker-controlled translation content or parameter placed inside an iframe srcdoc attribute survives sanitization as character references; the browser decodes and parses them as a nested same-origin document, executing script in the app origin.
**Escalation:** Chained with GHSA-8rc2-428q-7ww3: named values are unescaped when a list is also passed, so an iframe srcdoc in a named value reaches the sanitizer as markup even with a benign message like `{0} {name}`.
**Insight:** Sanitizers that neutralize by emitting HTML character references are undone by any context that re-decodes entities before parsing (srcdoc, nested documents); audit attribute values that are themselves parsed as documents.

## Proof of concept (copied exactly from the original report)

**PoC iframe srcdoc translation message**

```
import { createI18n } from 'vue-i18n'

const i18n = createI18n({
  legacy: false,
  locale: 'en',
  escapeParameter: true,
  messages: {
    en: { message: '<iframe srcdoc="<b>x</b>"></iframe>' }
  }
})

console.log(i18n.global.t('message'))
// v11.4.13: <iframe srcdoc="&lt;b&gt;x&lt;/b&gt;"></iframe>
```

