Patch Forecast
Amber warning
Patch this week.

CVE-2026-88058 · GHSA-j3r3-mxqp-r2p4

Angular SSR: XSS via Unescaped Processing Instruction (<?...?>) Nodes in Fallback Raw-Content Elements

Risk score
70/100
CVSS
8.6 v4.0
Exploit chance (30 days)
0.3%
Published
28 Sep 2026

Open in the live forecast Today's forecast

What to know

What it is
An XSS vulnerability exists in @angular/platform-server during server-side rendering (SSR) HTML serialization of ProcessingInstruction DOM nodes (<?target data?>, nodeType === 7) when nested inside fallback raw-content elements (<noscript>, <iframe>, <noembed>, <noframes>). While processing instruction data escaped > …
Affected
@angular/platform-server (npm) >= 22.0.0, < 22.1.4; @angular/platform-server (npm) >= 21.0.0, < 21.2.22; @angular/platform-server (npm) >= 20.0.0, < 20.3.30; @angular/platform-server (npm) <= 19.2.25
Fix
Upgrade @angular/platform-server to 22.1.4 or 21.2.22 or 20.3.30 (whichever matches your release line) or later.
Exploitation
Public proof of concept

Story map

Story map: @angular/platform-serverTHE FLAWSTHE FIXCVE-2026-88058Angular SSR: XSS via UnescapedProcessing Instruction (<?...?>)Nodes in Fallback…CVSS 8.6 · EPSS 0%CVE-2026-101895Angular SSR: Denial of Service(DoS) via Infinite Loop onMalformed DOCTYPECVSS 8.7 · EPSS 1%Upgrade…20.3.31 · 21.2.23 · 22.1.6or later on your release lineWho is exposed@angular/platform-server(npm) >= 22.0.0, < 22.1.6;@angular/platform-server(npm) >= 21.0.0, < 21.2.23;@angular/platform-server…AMBER · PATCH THIS WEEK@angular/platform-serverAngular is a developmentplatform for building mobile anddesktop web applications usingTypeScript/JavaScript andother languages. Prior to20.3.31, 21.2.23, and 22.1.6, the@angular/platform-server…Where it standsPublic proof of conceptCONNECTS TOSame weaknessCross-site scripting (CWE-79)399 other warnings in 30 days →
Story map: the flaws, the fix, how it unfolded and what it connects to. Boxes link to the record or article.

At a glance

@angular/platform-server: Amber, patch this week. Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages. Prior to 20.3.31, 21.2.23, and 22.1.6, the @angular/platform-server DOM emulation parser can enter an infinite synchronous loop when Angular server-side rendering processes attacker-contr…

The flaws

  • CVE-2026-88058: Angular SSR: XSS via Unescaped Processing Instruction (<?...?>) Nodes in Fallback Raw-Content Elements (CVSS 8.6 · EPSS 0%)
  • CVE-2026-101895: Angular SSR: Denial of Service (DoS) via Infinite Loop on Malformed DOCTYPE (CVSS 8.7 · EPSS 1%)

The fix

Upgrade @angular/platform-server: 20.3.31 · 21.2.23 · 22.1.6 or later on your release line

Who is exposed: @angular/platform-server (npm) >= 22.0.0, < 22.1.6; @angular/platform-server (npm) >= 21.0.0, < 21.2.23; @angular/platform-server (npm) >= 20.0.0, < 20.3.31; @angular/platform-server (npm) <= 19.2.25

Where it stands

  • Public proof of concept

Connects to

Why it is Amber

  • CVSS 8.6 high
  • Public exploit or proof of concept referenced
  • Remotely exploitable without logging in
  • On your watchlist: npm

Affected packages

PackageEcosystemVulnerableFixed in
@angular/platform-servernpm>= 22.0.0, < 22.1.422.1.4
@angular/platform-servernpm>= 21.0.0, < 21.2.2221.2.22
@angular/platform-servernpm>= 20.0.0, < 20.3.3020.3.30
@angular/platform-servernpm<= 19.2.25No fix yet

References

Original description

### Summary An XSS vulnerability exists in `@angular/platform-server` during server-side rendering (SSR) HTML serialization of `ProcessingInstruction` DOM nodes (`<?target data?>`, `nodeType === 7`) when nested inside fallback raw-content elements (`<noscript>`, `<iframe>`, `<noembed>`, `<noframes>`). While processing instruction data escaped `>` to `&gt;`, it did not check for or escape matching closing tags of ancestor fallback elements (e.g., `</noscript>`). When rendered in a browser with scripting enabled, an unescaped closing tag sequence in a processing instruction prematurely closes the fallback raw-content tag and causes subsequent sibling elements to execute as live HTML. ### Technical Description In HTML5 parsing, fallback raw-content elements (`<noscript>`, `<iframe>`, `<noembed>`, `<noframes>`) place the browser's HTML tokenizer into `RAWTEXT` mode. In `RAWTEXT` mode, processing instruction tokens (`<?...?>`) are treated as literal raw text rather than bogus comments, and the parser ignores `>` or `?>`. The only token sequence that terminates the container is an end tag matching the container tag name (`</noscript`, `</iframe`, etc.). During server-side HTML serialization, processing instruction nodes previously only replaced `>` with `&gt;` (preventing bogus comment breakouts in normal HTML data states) but left `<` untouched. Crucially, processing instruction serialization never inspected ancestor fallback raw-content tags. As a result, if a `ProcessingInstruction` node inside `<noscript>` contained `</noscript ` in its data payload, it was emitted unescaped as `<?x </noscript ?>`. ### Impact & Reachability * **Reachability**: Processing instruction nodes cannot be authored directly through standard Angular template syntax (which parses `<?...>` into comment nodes in DOM position). Reaching this vulnerability requires application or library code calling `inject(DOCUMENT).createProcessingInstruction(target, data)` or `Renderer2` DOM insertion methods with untrusted user input passed to `data` inside a fallback raw-content container. * **Impact**: In applications that programmatically construct processing instruction nodes inside fallback elements during server-side rendering, an attacker controlling the processing instruction data can break out of the container and execute arbitrary JavaScript in victims' browsers. ### Proof of Concept (Minimal Reproduction) ```ts import { Component, ElementRef, Renderer2, inject, DOCUMENT, AfterViewInit } from '@angular/core'; @Component({ selector: 'app-root', standalone: true, template: `<noscript id="host"></noscript>` }) export class AppComponent implements AfterViewInit { private r = inject(Renderer2); private el = inject(ElementRef); private doc = inject(DOCUMENT); ngAfterViewInit() { const host = this.el.nativeElement.querySelector('#host'); // Attacker-controlled input passed as Processing Instruction data const pi = this.doc.createProcessingInstruction('x', '</noscript '); this.r.appendChild(host, pi); // Sibling markup that should remain inert inside <noscript> const img = this.r.createElement('img'); this.r.setAttribute(img, 'src', 'x'); this.r.setAttribute(img, 'onerror', 'alert("SSR_PI_XSS")'); this.r.appendChild(host, img); } } ``` **Vulnerable SSR Output**: ```html <noscript><?x </noscript ?><img src="x" onerror="alert('SSR_PI_XSS')"></noscript> ``` ### Workarounds * Avoid passing untrusted user input into `document.createProcessingInstruction(target, data)` when the node is inserted into `<noscript>`, `<iframe>`, `<noembed>`, or `<noframes>` during server-side rendering. * Manually sanitize or replace `<` with `&lt;` in any untrusted data passed to processing instruction nodes on the server.

Last activity 28 Sep 2026. Patch Forecast updates every hour.