CVE-2026-88060
Medium · 6.1CVSS
6.1
EPSS
0.4%
Published
Sep 10, 2026
CISA due date
—
Cloudanix analysis
A bug in how Angular builds pages on the server can let an attacker run their own code in someone’s browser if that person opens a poisoned page, which can lead to stolen logins and unauthorized actions.
- Exploitation
- Requires User Interaction
- Attacker needs
- None
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- Web Framework
- Class
- XSS
- Remediation
- Upgrade
- Effort
- Low
- Patch risk
- Low
What it actually does
Angular server-side rendering in @angular/platform-server incorrectly serializes untrusted template content nested in HTML fallback raw-content elements (noscript, iframe, noembed, noframes). The Domino serializer stops at the DocumentFragment used by template.content and does not escape matching closing tags in comments, text nodes, or certain raw elements. A browser HTML5 RAWTEXT parser then exits the inert container and treats trailing markup as live DOM, yielding cross-site scripting with arbitrary JavaScript in the application's origin. Standard interpolation via comments or text is reachable without relaxed schemas; Renderer2-built DOM is unconditionally affected.
Why it matters to the business
Internet-facing Angular SSR applications can deliver pages that run attacker-controlled script in users' browsers, enabling session and token theft, account takeover, unauthorized actions as the victim, and data exfiltration from the application origin. An exploit is already available and the issue has been public for about four weeks, so unpatched SSR deployments that bind untrusted data into affected template structures should be treated as exposed. User interaction (opening a crafted or stored page) is required, but no privileges are needed to attempt exploitation.
How an attack unfolds
An unauthenticated attacker finds an Angular SSR path that interpolates untrusted input into template content inside a fallback raw-content element, or that builds equivalent DOM with Renderer2. They submit input whose serialized form includes a closing tag the serializer does not escape. The SSR HTML is then served to a victim (reflected parameter, stored content, or shared link). The victim's browser treats the unescaped closer as ending the inert container, parses the remainder as active markup, and executes JavaScript in the Angular origin, which the attacker uses to steal session material or act as the user.
How to fix it
Upgrade Angular / @angular/platform-server to 20.3.30 (20.x), 21.2.22 (21.x), or 22.1.4 (22.x) or later. If you cannot patch immediately, stop interpolating untrusted data into templates nested in noscript, iframe, noembed, or noframes; avoid CUSTOM_ELEMENTS_SCHEMA and NO_ERRORS_SCHEMA unless strictly required; and do not use Renderer2 to insert untrusted strings into those structures. Apply contextual HTML encoding of untrusted data before SSR as defense in depth, and deploy a strict Content-Security-Policy that disallows inline script to reduce exploitability until the upgrade is complete.
How to confirm the fix worked
Confirm installed @angular/platform-server (and related Angular packages) is at least 20.3.30, 21.2.22, or 22.1.4 on the corresponding major line. Inventory SSR routes that bind user- or partner-controlled data into templates or Renderer2 DOM. After upgrade, re-render those routes and verify fallback raw-content regions do not contain unescaped closing tags from untrusted input. Review schemas so CUSTOM_ELEMENTS_SCHEMA and NO_ERRORS_SCHEMA are not enabled without need.
Typical attack path
- Locate an Angular app using @angular/platform-server on a release prior to 20.3.30, 21.2.22, or 22.1.4
- Identify a SSR view that interpolates untrusted data into template content inside noscript, iframe, noembed, or noframes, or that constructs that DOM with Renderer2
- Submit untrusted input that survives serialization with an unescaped closing tag for the fallback container
- Cause a user to load the resulting SSR page (link, stored content, or reflected request)
- Victim browser breaks out of the fallback element and runs attacker script in the application origin
- Abuse the victim session or steal credentials and tokens from that origin
How to detect it
This is client-side script execution after a poisoned SSR response, so look for the request that planted the input and the HTML that was served, not a distinct malware binary. Review HTTP access and WAF logs for SSR routes where query, path, or body values contain fallback-element closers or raw-text closers around the time users reported odd page behavior. Compare cached or logged SSR HTML for unescaped closing tags inside noscript, iframe, noembed, or noframes followed by unexpected markup. Use CSP violation reports, browser XSS auditor or Trusted Types breaks, and RUM/error telemetry showing script on SSR URLs that should not run inline script. If compromise is suspected, assume session cookies and origin storage on those pages may have been read.
- </noscript>
- </iframe>
- </noembed>
- </noframes>
- </xmp>
- </style>
- CUSTOM_ELEMENTS_SCHEMA
- NO_ERRORS_SCHEMA
- @angular/platform-server
What your security team should do
- Patch Angular SSR to 20.3.30, 21.2.22, or 22.1.4 immediately; treat as urgent because a public exploit exists even though this CVE is not in CISA KEV
- Inventory all apps using @angular/platform-server and any stored or cached SSR HTML generated before the fix
- Prioritize internet-facing SSR apps that render untrusted interpolation inside noscript, iframe, noembed, noframes, or via Renderer2
- Enforce CSP without unsafe-inline as a temporary compensating control and monitor CSP reports
- Hunt for historical exploitation using the detection guidance, then rotate sessions and tokens if suspicious SSR responses or XSS-like traffic are found
The record
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.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|
Related vulnerabilities
- CVE-2026-96379 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96382 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96368 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96361 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96362 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96360 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96357 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79
- CVE-2026-96358 Improper Neutralization of Input During Web Page Generation ("Cross-site Scripting")… CWE-79