Summary
Angular: SSR XSS via Unescaped <template> Content Across DocumentFragment Boundaries in Fallback Raw-Content Elements
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 -> </tag). However:
- Per DOM specifications, the children of a
<template>element reside in a separateDocumentFragment(template.content), whose ownparentNodeisnull. - The serializer's ancestor traversal previously only inspected element nodes. When traversing upward from a node inside
template.content, traversal terminated immediately at theDocumentFragmentboundary. - 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 (CUSTOM_ELEMENTS_SCHEMAorNO_ERRORS_SCHEMA). 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
Renderer2bypass template compiler schema checks entirely and are unconditionally affected.
Proof of Concept (Minimal Reproduction)
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("SSR_TEMPLATE_XSS")>';
}
Vulnerable SSR Output:
<noscript><template><xmp></noscript><img src=x onerror=alert("SSR_TEMPLATE_XSS")></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.
Impact
Untrusted input is rendered as active markup in a victim's browser, which can run script in their session. Typical impact: session or credential theft, and actions taken as the user.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
@angular/platform-server to 22.1.4 or later; @angular/platform-server to 21.2.22 or later; @angular/platform-server to 20.3.30 or later
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-88060? CVE-2026-88060 is a high-severity cross-site scripting (XSS) vulnerability in @angular/platform-server (npm), affecting versions >= 22.0.0, < 22.1.4. It is fixed in 22.1.4, 21.2.22, 20.3.30. Untrusted input is rendered as active markup in a victim's browser, which can run script in their session.
- Which versions of @angular/platform-server are affected by CVE-2026-88060? @angular/platform-server (npm) versions >= 22.0.0, < 22.1.4 is affected.
- Is there a fix for CVE-2026-88060? Yes. CVE-2026-88060 is fixed in 22.1.4, 21.2.22, 20.3.30. Upgrade to this version or later.
- Is CVE-2026-88060 exploitable, and should I be worried? Whether CVE-2026-88060 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-88060 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-88060?
- Upgrade
@angular/platform-serverto 22.1.4 or later - Upgrade
@angular/platform-serverto 21.2.22 or later - Upgrade
@angular/platform-serverto 20.3.30 or later
- Upgrade