Advisory Database
  • Advisories
  • Dependency Scanning
  1. npm
  2. ›
  3. @vue/server-renderer
  4. ›
  5. GHSA-g2v6-rqmx-r4w6

GHSA-g2v6-rqmx-r4w6: @vue/server-renderer: XSS via missing CR in attribute-name blacklist

October 5, 2026

@vue/server-renderer was investigated specifically because it’s the one place in Vue where template rendering output becomes a real HTTP response body – a genuine server-side trust boundary, unlike client-side rendering which only ever affects the same browser session that’s already running the app’s own JS.

ssrRenderAttrs() (in packages/server-renderer/src/helpers/ssrRenderAttrs.ts) is what compiled SSR output calls for something like <div v-bind="userObject">. It loops over the object’s own keys and, for each one, renders it as an HTML attribute:

export function ssrRenderDynamicAttr(
key: string,
value: unknown,
tag?: string,
): string {
if (!isRenderableAttrValue(value)) {
return ``
}
const attrKey = ...
if (isBooleanAttr(attrKey) || ...) {
return includeBooleanAttr(value) ? ` ${attrKey}` : ``
} else if (isSSRSafeAttrName(attrKey)) {
return value === '' ? ` ${attrKey}` : ` ${attrKey}="${escapeHtml(value)}"`
} else {
console.warn(`[@vue/server-renderer] Skipped rendering unsafe attribute name: ${attrKey}`)
return ``
}
}

The value always goes through escapeHtml() – that part is correctly and consistently applied everywhere in this file. But the attribute name (attrKey) is only checked against a character blacklist, then spliced directly into the output with no escaping of its own:

// packages/shared/src/domAttrConfig.ts
const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/

export function isSSRSafeAttrName(name: string): boolean {
if (attrValidationCache.hasOwnProperty(name)) {
return attrValidationCache[name]
}
const isUnsafe = unsafeAttrCharRE.test(name)
if (isUnsafe) {
console.error(`unsafe attribute name: ${name}`)
}
return (attrValidationCache[name] = !isUnsafe)
}

That blacklist covers: >, /, =, ", apostrophe, tab (U+0009), line feed (U+000A), form feed (U+000C), and space (U+0020). It does not cover U+000D – carriage return (CR, written as \r in JS).

That matters because of how browsers actually parse HTML. Per the WHATWG HTML parsing spec, the very first step (“preprocessing the input stream”) converts every \r not followed by \n into a \n before the tokenizer even starts. So a raw \r sitting inside what Vue intends as a single attribute name gets turned into a real line feed by the browser – and a line feed is one of the characters that terminates an attribute name and starts a new one. The blacklist checks the string as Vue sees it before the browser gets to reinterpret it, and that’s exactly the gap.

Below is a fresh clone of this repo, confirming the exact commit, the exact vulnerable line, and zero modification to the source:

References

  • github.com/advisories/GHSA-g2v6-rqmx-r4w6
  • github.com/vuejs/core/commit/a2b40db9a83b36ed9da3a16403cf8f040262d73f
  • github.com/vuejs/core/pull/15266
  • github.com/vuejs/core/releases/tag/v3.5.42
  • github.com/vuejs/core/releases/tag/v3.6.0-rc.6
  • github.com/vuejs/core/security/advisories/GHSA-g2v6-rqmx-r4w6

Code Behaviors & Features

Detect and mitigate GHSA-g2v6-rqmx-r4w6 with GitLab Dependency Scanning

Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Dependency Scanning using SBOM also detects vulnerabilities from proprietary advisories that this site does not include. Learn more about Dependency Scanning using SBOM →

Affected versions

All versions before 3.5.42, all versions starting from 3.6.0-rc.0 before 3.6.0-rc.6

Fixed versions

  • 3.5.42
  • 3.6.0-rc.6

Solution

Upgrade to versions 3.5.42, 3.6.0-rc.6 or above.

Impact 7.2 HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N

Learn more about CVSS

Weakness

  • CWE-116: Improper Encoding or Escaping of Output
  • CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Source file

npm/@vue/server-renderer/GHSA-g2v6-rqmx-r4w6.yml

Spotted a mistake? Edit the file on GitLab.

  • Site Repo
  • About GitLab
  • Terms
  • Privacy Statement
  • Contact

Page generated Sun, 08 Nov 2026 00:16:29 +0000.