CVE-2026-88060: Angular: SSR XSS via Unescaped <template> Content Across DocumentFragment Boundaries in Fallback Raw-Content Elements

Published Sep 10, 2026
·
Updated

Summary An XSS vulnerability exists in @angular/platform-server during server-side rendering (SSR) HTML serialization when traversing ancestor tags across <template> element boundaries. When an application renders untrusted user input within raw-text tags (<xmp>, <style>, <script>), comments, or text nodes inside a <template> that is nested within a fallback raw-content element (<noscript>, <iframe>, <noembed>, <noframes>), matching closing tags (e.g., </noscript>) are not escaped during HTML serialization. When rendered in a browser, this unescaped closing tag prematurely terminates the fallback container and executes trailing markup as active DOM elements.

Technical Description In HTML5 parsing, fallback raw-content elements (<noscript>, <iframe>, <noembed>, <noframes>) place the browser's tokenizer into RAWTEXT mode. In this mode, inner content is parsed as literal text until an end tag matching the container tag name (e.g., </noscript>) is encountered.

To prevent XSS breakout vectors during SSR serialization, the DOM serializer inspects a node's ancestors to escape any matching fallback closing tags (</tag -> &lt;/tag). However: 1. Per DOM specifications, the children of a <template> element reside in a separate DocumentFragment (template.content), whose own parentNode is null. 2. The serializer's ancestor traversal previously only inspected element nodes. When traversing upward from a node inside template.content, traversal terminated immediately at the DocumentFragment boundary. 3. Because traversal stopped before reaching the outer document tree, enclosing fallback raw-content ancestors (such as <noscript> or <iframe>) were not discovered. As a result, closing sequences like </noscript> within <template> content were emitted unescaped.

Impact & Reachability Framework Guarantee Bypass: Angular guarantees that standard text interpolation ({{ userInput }} bound as element text content) is safe by default without manual sanitization. This vulnerability bypasses that guarantee during SSR HTML serialization when untrusted input is interpolated inside template content within fallback containers. Template Authoring: Writing literal <xmp> or <style> directly inside a component's <template> markup requires relaxed template schema checks (CUSTOMELEMENTSSCHEMA or NOERRORSSCHEMA). However, standard HTML comments and text nodes inside <template> within <noscript> are reachable without relaxed schemas. Imperative DOM Construction: Components or directives that construct DOM structures imperatively via Renderer2 bypass template compiler schema checks entirely and are unconditionally affected.

Proof of Concept (Minimal Reproduction) ts import { Component } from '@angular/core';

@Component({ selector: 'app-root', standalone: true, template: <noscript> <template> <xmp>{{ payload }}</xmp> </template> </noscript> }) export class AppComponent { // Attacker-controlled input bound via standard text interpolation payload = '</noscript><img src=x onerror=alert("SSRTEMPLATEXSS")>'; } Vulnerable SSR Output: html <noscript><template><xmp></noscript><img src=x onerror=alert("SSRTEMPLATEXSS")></xmp></template></noscript>

Workarounds Avoid rendering untrusted user input inside <template> elements nested within <noscript>, <iframe>, <noembed>, or <noframes> in server-rendered templates. Avoid programmatic DOM assembly of <template> elements inside fallback containers when handling untrusted data.

Other sources

Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.30, 21.2.22, and 22.1.4, Angular server-side rendering (SSR) in @angular/platform-server serializes untrusted input inside template content nested in fallback raw-content elements such as noscript, iframe, noembed, and noframes. The Domino serializer's fallbackRawContentTags traversal stopped at the DocumentFragment used by template.content, so matching closing tags in xmp, style, script, comments, or text nodes were not escaped. Standard interpolation with comments or text nodes is reachable without relaxed schemas; literal xmp or style requires CUSTOMELEMENTSSCHEMA or NOERRORSSCHEMA, while Renderer2 imperative DOM construction is unconditionally affected. When HTML5 RAWTEXT browser parsing encounters the unescaped closing tag, it exits the fallback container and interprets trailing markup as active DOM elements, enabling arbitrary JavaScript execution. This issue is fixed in versions 20.3.30, 21.2.22, and 22.1.4.

MITRE

Affected Software

7 affected componentsFixes available
Google Angular>0<=20.3.29
Angular>0<=21.2.21
Angular>0<=22.1.3
npm/@angular/platform-server<=19.2.25
npm/@angular/platform-server>=20.0.0<20.3.30
20.3.30
npm/@angular/platform-server>=21.0.0<21.2.22
21.2.22
npm/@angular/platform-server>=22.0.0<22.1.4
22.1.4

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@angular/platform-server to a version that resolves this vulnerability.

    Fixed in 20.3.30
  2. Upgrade

    Upgrade npm/@angular/platform-server to a version that resolves this vulnerability.

    Fixed in 21.2.22
  3. Upgrade

    Upgrade npm/@angular/platform-server to a version that resolves this vulnerability.

    Fixed in 22.1.4
  4. Upgrade

    Upgrade @angular/platform-server to a version that resolves this vulnerability.

    Fixed in 20.3.30
  5. Upgrade

    Upgrade @angular/platform-server to a version that resolves this vulnerability.

    Fixed in 21.2.22
  6. Upgrade

    Upgrade @angular/platform-server to a version that resolves this vulnerability.

    Fixed in 22.1.4
  7. Configuration

    Do not rely on relaxed template schema checks (CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA) to author literal <xmp> or <style> directly in component <template> markup; refactor to avoid raw-content tag patterns in SSR templates.

    Angular template compiler CUSTOM_ELEMENTS_SCHEMA / NO_ERRORS_SCHEMA = avoid using when authoring literal <xmp> or <style> directly in component <template> markup (not required for escaping; used only to relax template schema checks)
  8. Configuration

    When performing SSR, avoid rendering untrusted user input inside <template> elements nested within fallback raw-content elements (<noscript>, <iframe>, <noembed>, <noframes>).

    Angular SSR application templates untrusted-data-rendering-in-fallback-raw-content-containers = avoid rendering untrusted input within <template> elements nested inside <noscript>, <iframe>, <noembed>, or <noframes> in server-rendered templates
  9. Configuration

    Avoid programmatic/imperative DOM assembly of <template> elements using Renderer2 (imperative DOM construction bypasses template compiler schema checks and is unconditionally affected).

    Angular SSR/DOM handling imperative-dom-assembly-of-<template> = avoid

Event History

Sep 10, 2026
CVE Published
via MITRE·07:04 PM
Data Sourced
via MITRE·07:04 PM
DescriptionWeakness
Advisory Published
via GitHub·08:25 PM
Data Sourced
via GitHub·08:25 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

Which applications are exposed to this issue?

Applications using Angular SSR through @angular/platform-server are exposed when untrusted input is serialized inside template content nested in fallback raw-content elements such as noscript, iframe, noembed, or noframes. Client-only Angular applications are not identified as affected by the provided data.

2

Does exploitation require permissive Angular schemas?

No. Standard interpolation using comments or text nodes is reachable without relaxed schemas. Creating literal xmp or style elements requires CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA, but imperative DOM construction with Renderer2 is described as unconditionally affected.

3

What does an attacker need to control?

An attacker needs to supply untrusted content that is rendered by SSR in the affected template-content context. The payload must include a closing tag that HTML5 RAWTEXT parsing recognizes, allowing trailing markup to be interpreted as active DOM and execute JavaScript.

4

Which versions contain the fix?

The issue is fixed in Angular versions 20.3.30, 21.2.22, and 22.1.4. Versions prior to those releases are affected according to the advisory.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203