- A GitHub advisory says Vue's server renderer misses the carriage return character, so a crafted attribute name can become a self-running script in the browser.
- It applies only when an app builds HTML attributes from keys that outsiders can influence. Values are escaped correctly, and the reporter says client-side Vue is not affected.
- Check whether your server-rendered Vue apps spread user-influenced objects onto elements. The advisory links two Vue releases but does not say they contain a fix, so verify in their release notes.
The check ran before the browser read the text
A safety check is only as good as its match with the thing that reads the result. This advisory shows a gap between two readers of the same string. Vue's server code inspected one version of it. The browser then interpreted another.
The GitHub Advisory Database published the report on October 5, 2026. It covers @vue/server-renderer, the part of Vue that turns templates into HTML on the server. The reporter chose it because it is the one place where Vue output becomes a real HTTP response body. The reporter calls that a genuine trust boundary.
How one character becomes three attributes
The function ssrRenderAttrs() writes an object's keys out as HTML attribute names. The advisory says values pass through escapeHtml() correctly. Names do not get escaped. They are only checked against a list of banned characters.
That list covers the greater-than sign, slash, equals sign, double and single quotes, tab, line feed, form feed and space. It leaves out the carriage return, the character written \r in JavaScript.
The WHATWG HTML parsing rules explain why that matters. Before a browser tokenizes HTML, it converts any carriage return not followed by a line feed into a line feed. The browser treats a line feed as the end of one attribute name and the start of the next.
So the name x\rautofocus\ronfocus passes Vue's check as one harmless name. The browser reads it as three things: an empty x attribute, an autofocus attribute and an onfocus event handler. Autofocus fires the focus event on page load. The injected script then runs with no click or hover.
Who is actually exposed
The reporter is candid about the limits. An app is only reachable if it binds an object where the keys, and not only the values, come from a source the developer does not fully control. This happens through v-bind="object" or its compiled form.
Binding untrusted values is the everyday Vue pattern, and escapeHtml() handles it. Binding untrusted keys is rarer. The advisory's examples are a CMS or form builder where a less-trusted role configures field names, and helpers that spread external data onto an element.
The reporter says client-side Vue is not affected. In their account, the browser's setAttribute() call validates attribute names. They found no way to reach this bug through that path. The issue is in server-side rendering only.
Where the conditions are met, the advisory describes stored XSS. It says the payload runs for every visitor who receives that rendered output.
That count shows how many sites in the sample use Vue. It does not show how many render on the server or bind untrusted keys. Exposure is a question for each application.
The lesson is in the list
The advisory's suggested fix is to add U+000D to the character list in packages/shared/src/domAttrConfig.ts. It adds a broader point. The WHATWG definition of ASCII whitespace has five characters: tab, line feed, form feed, carriage return and space. Vue's list had four of them. In the reporter's words, this kind of list is easy to leave a gap in.
This is the publication's view, not the advisory's. A banned-character list asks what the developer remembered to forbid. A permitted-character list asks what a name must look like to be safe. The first fails when a parser treats an unlisted character as a separator. The second is harder to get wrong. Any security control that screens text for another program to read should be tested against that program's own rules.
What to ask your teams
The reporter ran the attack against the published @vue/server-renderer 3.5.41 package without modifying it. They then inspected the latest source and the v3.6.0-rc.2 tag. Both contain the same faulty character pattern. The reporter did not identify any branch with a fix.
The advisory also links to two Vue releases, v3.5.42 and v3.6.0-rc.6. It does not say that either contains a fix. Have your team read those release notes and verify what they change before relying on them.
Then ask three questions. Which of our apps render Vue on the server? Do any spread an object onto an element when its keys come from a database, an API or a query string? Who can edit the field names that feed those objects?
If the answer to the last two is nobody, the exposure is narrow. If it is a customer-facing admin role, treat it as a priority for review. A single missing character was enough here, so the review should cover how your code checks names as well as values.
Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: GitHub Advisory Database.





