{"id":"CVE-2026-88060","revision":null,"records":[{"revision":"dbd2361c39d14290a1492e7179a0b493","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-88060","aliases":[],"title":"Angular: SSR XSS via Unescaped <template> Content Across DocumentFragment Boundaries in Fallback Raw-Content Elements","description":"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 CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA, 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.","state":0,"publishedAt":"2026-09-10T19:04:17.42+00:00","modifiedAt":"2026-09-10T19:20:56.297+00:00","affected":[{"ecosystem":"Vendor product","name":"angular","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"angular\",\n                    \"product\": \"angular\",\n                    \"versions\": [\n                        {\n                            \"version\": \"<= 19.2.25\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 20.0.0, < 20.3.30\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 21.0.0, < 21.2.22\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 22.0.0, < 22.1.4\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N","score":8.6,"severity":"HIGH"}],"references":["https://github.com/angular/angular/security/advisories/GHSA-v3p8-whq6-r5jg","https://github.com/angular/angular/commit/73d8bbd27cb46495426d4132975a1355b47ad915","https://github.com/angular/angular/commit/89b20568dfaee1ec8e0b3bcf1872acdddd2f4fef","https://github.com/angular/angular/commit/ba3bc47b20b3d12f5eb141ec9c651373ae4d15e8","https://github.com/angular/domino/commit/04f987dc08ff3736b427f50941adf1722458528f","https://github.com/angular/angular/releases/tag/v20.3.30","https://github.com/angular/angular/releases/tag/v21.2.22","https://github.com/angular/angular/releases/tag/v22.1.4"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-88060","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-88060","identifiers":["CVE-2026-88060"]},"retained":false,"historicalAffected":[]},{"revision":"aaa2be33ebe04dd5a8fac5e947a459bc","observedAt":"2026-11-11T17:03:31.312+00:00","statement":{"source":"euvd","id":"EUVD-2026-75703","aliases":["CVE-2026-88060","GHSA-v3p8-whq6-r5jg"],"title":"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 seria…","description":"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 CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA, 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.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N","score":8.6,"severity":null}],"references":["https://github.com/angular/angular/security/advisories/GHSA-v3p8-whq6-r5jg","https://github.com/angular/angular/commit/73d8bbd27cb46495426d4132975a1355b47ad915","https://github.com/angular/angular/commit/89b20568dfaee1ec8e0b3bcf1872acdddd2f4fef","https://github.com/angular/angular/commit/ba3bc47b20b3d12f5eb141ec9c651373ae4d15e8","https://github.com/angular/domino/commit/04f987dc08ff3736b427f50941adf1722458528f","https://github.com/angular/angular/releases/tag/v20.3.30","https://github.com/angular/angular/releases/tag/v21.2.22","https://github.com/angular/angular/releases/tag/v22.1.4"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-75703","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 10, 2026, 7:04:17 PM","dateUpdated":"Sep 10, 2026, 7:20:56 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-75703","identifiers":["EUVD-2026-75703","CVE-2026-88060","GHSA-v3p8-whq6-r5jg"]},"retained":false,"historicalAffected":[]},{"revision":"6289991a6d744022ad3a5b1a2b79fe53","observedAt":"2026-10-25T16:19:22.228+00:00","statement":{"source":"nvd","id":"CVE-2026-88060","aliases":[],"title":"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 seria…","description":"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 CUSTOM_ELEMENTS_SCHEMA or NO_ERRORS_SCHEMA, 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.","state":0,"publishedAt":"2026-09-10T19:17:42.107+00:00","modifiedAt":"2026-09-29T18:44:06.647+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · security-advisories@github.com · Secondary","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":8.6,"severity":"HIGH"},{"system":"CVSS 3.1 · nvd@nist.gov · Primary","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N","score":6.1,"severity":"MEDIUM"}],"references":["https://github.com/angular/angular/commit/73d8bbd27cb46495426d4132975a1355b47ad915","https://github.com/angular/angular/commit/89b20568dfaee1ec8e0b3bcf1872acdddd2f4fef","https://github.com/angular/angular/commit/ba3bc47b20b3d12f5eb141ec9c651373ae4d15e8","https://github.com/angular/angular/releases/tag/v20.3.30","https://github.com/angular/angular/releases/tag/v21.2.22","https://github.com/angular/angular/releases/tag/v22.1.4","https://github.com/angular/angular/security/advisories/GHSA-v3p8-whq6-r5jg","https://github.com/angular/domino/commit/04f987dc08ff3736b427f50941adf1722458528f"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-88060","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-79","CWE-116"],"productCriteria":["cpe:2.3:a:angular:angular:*:*:*:*:*:node.js:*:*"],"sourceDates":{"published":"2026-09-10T19:17:42.107","lastModified":"2026-09-29T18:44:06.647"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-88060","identifiers":["CVE-2026-88060"]},"retained":false,"historicalAffected":[]},{"revision":"4ddf5daac8564eff81d39d1b5df065bf","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-v3p8-whq6-r5jg","aliases":["CVE-2026-88060"],"title":"Angular: SSR XSS via Unescaped <template> Content Across DocumentFragment Boundaries in Fallback Raw-Content Elements","description":"### Summary\nAn 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.\n\n### Technical Description\nIn 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.\n\nTo 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:\n1. Per DOM specifications, the children of a `<template>` element reside in a separate `DocumentFragment` (`template.content`), whose own `parentNode` is `null`.\n2. 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.\n3. 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.\n\n### Impact & Reachability\n* **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.\n* **Template Authoring**: Writing literal `<xmp>` or `<style>` directly inside a component's `<template>` markup requires relaxed template schema checks (`CUSTOM_ELEMENTS_SCHEMA` or `NO_ERRORS_SCHEMA`). However, standard HTML comments and text nodes inside `<template>` within `<noscript>` are reachable without relaxed schemas.\n* **Imperative DOM Construction**: Components or directives that construct DOM structures imperatively via `Renderer2` bypass template compiler schema checks entirely and are unconditionally affected.\n\n### Proof of Concept (Minimal Reproduction)\n```ts\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  template: `\n    <noscript>\n      <template>\n        <xmp>{{ payload }}</xmp>\n      </template>\n    </noscript>\n  `\n})\nexport class AppComponent {\n  // Attacker-controlled input bound via standard text interpolation\n  payload = '</noscript><img src=x onerror=alert(\"SSR_TEMPLATE_XSS\")>';\n}\n```\n**Vulnerable SSR Output**:\n```html\n<noscript><template><xmp></noscript><img src=x onerror=alert(\"SSR_TEMPLATE_XSS\")></xmp></template></noscript>\n```\n\n### Workarounds\n* Avoid rendering untrusted user input inside `<template>` elements nested within `<noscript>`, `<iframe>`, `<noembed>`, or `<noframes>` in server-rendered templates.\n* Avoid programmatic DOM assembly of `<template>` elements inside fallback containers when handling untrusted data.","state":0,"publishedAt":"2026-09-10T20:25:25+00:00","modifiedAt":"2026-09-25T05:30:06.0824836+00:00","affected":[{"ecosystem":"npm","name":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"22.0.0"},{"kind":"fixed","version":"22.1.4"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"21.0.0"},{"kind":"fixed","version":"21.2.22"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"20.0.0"},{"kind":"fixed","version":"20.3.30"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"@angular/platform-server","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"last_affected","version":"19.2.25"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"HIGH"}],"references":["https://github.com/angular/angular/security/advisories/GHSA-v3p8-whq6-r5jg","https://github.com/angular/angular/commit/73d8bbd27cb46495426d4132975a1355b47ad915","https://github.com/angular/angular/commit/89b20568dfaee1ec8e0b3bcf1872acdddd2f4fef","https://github.com/angular/angular/commit/ba3bc47b20b3d12f5eb141ec9c651373ae4d15e8","https://github.com/angular/domino/commit/04f987dc08ff3736b427f50941adf1722458528f","https://github.com/angular/angular","https://github.com/angular/angular/releases/tag/v20.3.30","https://github.com/angular/angular/releases/tag/v21.2.22","https://github.com/angular/angular/releases/tag/v22.1.4"],"sourceUrl":"https://github.com/advisories/GHSA-v3p8-whq6-r5jg","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-v3p8-whq6-r5jg","identifiers":["GHSA-v3p8-whq6-r5jg","CVE-2026-88060"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-12T06:54:08.8081877+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-12T06:54:08.8081877+00:00","lastSuccessAt":"2026-11-12T06:54:09.4926633+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:09.4926642+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-64752486c567b55b31fb0d7225f5222bcd0019564ac0ac5f0649e242c7b19299-031557bd84075d0efeb8f81d38e7e201c5767c1ec5ad4deb9375464dfdb790d3","complete":true,"records":424595,"lastAttemptAt":"2026-11-12T06:53:59.6712569+00:00","lastSuccessAt":"2026-11-12T06:53:59.6124706+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:53:59.6712569+00:00","snapshotPublishedAt":"2026-11-12T06:27:50+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-570328139368428ca550af1570d01579","complete":true,"records":13760,"lastAttemptAt":"2026-11-12T06:55:06.9273282+00:00","lastSuccessAt":"2026-11-12T06:55:06.923+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:55:06.923+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-12T06:54:08.8081877+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-12T06:54:08.8081877+00:00","lastSuccessAt":"2026-11-12T06:54:09.7509822+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:09.7509833+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-5bd6a0be90c14da3820334c987af617f","complete":true,"records":13760,"lastAttemptAt":"2026-11-12T06:54:37.2126404+00:00","lastSuccessAt":"2026-11-12T06:54:37.209+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:37.209+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-12T06:54:07.7500838+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:07.7500838+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-12T06:54:05.0323741+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:05.0323741+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-baa8362b4daf9e5f39d5563775a55935e7b442c0735d33274a921579ce4a0d66","complete":true,"records":3093,"lastAttemptAt":"2026-11-12T06:54:08.5688182+00:00","lastSuccessAt":"2026-11-11T13:00:02.5446881+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:08.5688182+00:00","snapshotPublishedAt":"2026-11-11T12:47:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-eb5176d73e87a862c4cae7484f3fd31f7d170139114b3e99e25926d661f6435b","complete":true,"records":231700,"lastAttemptAt":"2026-11-12T06:54:05.6319464+00:00","lastSuccessAt":"2026-11-12T05:58:39.2691741+00:00","error":null,"lastVerifiedAt":"2026-11-12T06:54:05.6319464+00:00","snapshotPublishedAt":"2026-11-12T05:48:10+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}