VYPR
`, ``, or ``), the index offset calculation in `domino`'s replacement logic shifted.\n\nThis misalignment caused `domino` to fail to replace or escape the closing tag, leaving it raw and unescaped in the output HTML.\n\nAn attacker who controls the dynamic text can supply a payload containing both an astral Unicode character and a closing tag (e.g., `😀`). When serialized on the server during SSR, the browser parses the unescaped closing tag, exits the raw-text context early, and executes the subsequent `
High severity8.6GHSA Advisory· Published Jun 15, 2026

@angular/platform-server: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

CVE-2026-50555

Description

Unicode index alignment bug in domino's raw-text escaping causes XSS in Angular SSR when user-controlled data contains astral characters.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Unicode index alignment bug in domino's raw-text escaping causes XSS in Angular SSR when user-controlled data contains astral characters.

Vulnerability

A cross-site scripting (XSS) vulnerability exists in @angular/platform-server's DOM emulation dependency domino when serializing the content of raw-text elements (``), the index offset miscalculation causes domino to fail to escape the closing tag, leaving it raw in the output HTML. Affected versions are Angular/core before 19.2.25, 20.3.24, 21.2.16, and 22.0.0-rc.2 [1][2][3].

Exploitation

An attacker who controls dynamic text bound inside a raw-text element can supply a payload such as 😀. During server-side rendering (SSR), when domino serializes the content, the closing tag is not escaped due to the alignment bug. The browser then parses the unescaped closing tag, exits the raw-text context, and executes the subsequent `` block. No authentication or special network position is required—only the ability to inject user-controlled text into a raw-text element in an Angular SSR template [2][3].

Impact

Successful exploitation results in same-origin Cross-Site Scripting (XSS). The attacker can execute arbitrary JavaScript in the context of the victim's session on the affected page, leading to session hijacking, credential theft, unauthorized actions on behalf of the user, or page defacement [2][3].

Mitigation

The vulnerability is patched in Angular versions 19.2.25, 20.3.24, 21.2.16, and 22.0.0-rc.2. Users should update their @angular/platform-server dependency accordingly. If immediate update is not possible, workarounds include: avoiding binding user-controlled values inside `` or other raw-text elements, and sanitizing any user input placed inside raw-text elements to explicitly strip closing tags before passing it to the template [1][2][3].

AI Insight generated on Jun 15, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

1
f74cccd49628

fixup! fix: Escapes </noscript in raw text when scripting enabled

https://github.com/angular/dominoSkyZeroZxMay 26, 2026via ghsa-ref
2 files changed · +4 7
  • lib/NodeUtils.js+3 4 modified
    @@ -29,6 +29,7 @@ var hasRawContent = {
       XMP: true,
       IFRAME: true,
       NOEMBED: true,
    +  NOSCRIPT: true,
       NOFRAMES: true,
       PLAINTEXT: true
     };
    @@ -195,8 +196,7 @@ function serializeOne(kid, parent) {
             // If an element can have raw content, this content may
             // potentially require escaping to avoid XSS.
             var upperTag = tagname.toUpperCase();
    -        if (hasRawContent[upperTag] ||
    -            (upperTag === 'NOSCRIPT' && kid.ownerDocument._scripting_enabled)) {
    +        if (hasRawContent[upperTag]) {
               ss = escapeMatchingClosingTag(ss, tagname);
             }
             if (html && extraNewLine[tagname] && ss.charAt(0)==='\n') s += '\n';
    @@ -214,8 +214,7 @@ function serializeOne(kid, parent) {
           else
             parenttag = '';
     
    -      if (hasRawContent[parenttag] ||
    -          (parenttag==='NOSCRIPT' && parent.ownerDocument._scripting_enabled)) {
    +      if (hasRawContent[parenttag]) {
             s += kid.data;
           } else {
             s += escape(kid.data);
    
  • test/xss.js+1 3 modified
    @@ -180,13 +180,11 @@ exports.styleMatchingClosingTagSkipsUnclosedCommentedContent = function () {
     };
     
     exports.noscriptMatchingClosingTagInRawText = function () {
    -  // Use a parsed document so `_scripting_enabled` is true, matching how
    -  // Angular SSR / platform-server uses domino. With scripting enabled,
       // <noscript> is a raw-text element on serialization and its text data
       // must have any `</noscript` closing-tag prefix escaped, otherwise an
       // attacker-controlled text payload can break out and inject a live
       // <script> sibling in the receiving browser.
    -  const document = domino.createDocument('<!doctype html><html><body></body></html>');
    +  const document = domino.createDocument('');
       const noscript = document.createElement('noscript');
       noscript.textContent = 'abc</noscript><script>alert(1)</script>';
       document.body.appendChild(noscript);
    

Vulnerability mechanics

Root cause

"Unicode index alignment bug in domino's raw-text element escaping logic causes closing tags to remain unescaped when astral characters precede them."

Attack vector

An attacker who controls dynamic text bound inside a raw-text element (e.g., `<iframe>`, `<script>`, `<style>`) can craft a payload containing an astral Unicode character (like an emoji) followed by a closing tag (e.g., `😀</iframe><script>alert(1)</script>`). Due to a UTF-16 index misalignment in domino's escaping logic, the closing tag is not escaped during server-side serialization. When the browser parses the SSR output, it interprets the unescaped closing tag, exits the raw-text context prematurely, and executes the subsequent `<script>` block, resulting in same-origin XSS.

Affected code

The vulnerability resides in `lib/NodeUtils.js` within the `serializeOne` function, where the escaping logic for raw-text elements (such as `<script>`, `<style>`, `<iframe>`) had a Unicode index alignment bug. The patch also modifies `test/xss.js` to remove the `_scripting_enabled` check for `<noscript>` elements.

What the fix does

The patch in `lib/NodeUtils.js` simplifies the raw-text detection logic by consolidating all raw-text elements (including `<noscript>`) into the `hasRawContent` map, removing the conditional check for `_scripting_enabled`. This ensures consistent escaping behavior regardless of scripting flags. The corresponding test in `test/xss.js` is updated to use a document without `_scripting_enabled`, confirming that `<noscript>` is now always treated as a raw-text element during serialization.

Preconditions

  • configThe application must use Angular's `@angular/platform-server` for server-side rendering (SSR).
  • inputUser-controlled or attacker-influenced data must be bound inside a raw-text element (e.g., ``, ``, ``) in the Angular template.
  • inputThe attacker's payload must include an astral Unicode character (e.g., an emoji) before the closing tag to trigger the index misalignment.

Generated on Jun 15, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.