CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-22610

The SVG Paradox: How Angular Forgot About 'xlink:href'

Amit Schendel
Amit Schendel
Senior Security Researcher

Feb 22, 2026·6 min read·129 visits

Executive Summary (TL;DR)

Angular's internal security schema failed to recognize that SVG `<script>` tags can execute code via `href` attributes, treating them as harmless links. This allows XSS via data bindings in SVG templates. Patch immediately to versions 19.2.18, 20.3.16, 21.0.7, or 21.1.0-rc.0.

A high-severity Cross-Site Scripting (XSS) vulnerability in the Angular Template Compiler allows attackers to bypass Angular's strict sanitization mechanisms. By leveraging SVG-specific attributes like `href` and `xlink:href` on `<script>` elements, attackers can inject malicious executable code that the framework mistakenly categorizes as safe URLs. This affects major versions of Angular Core, including v19, v20, and v21.

The Hook: When Paranoid Frameworks Blink

Angular is famous—or infamous, depending on who you ask—for being paranoid. It is the helicopter parent of JavaScript frameworks. It holds your hand, checks your inputs, and aggressively sanitizes anything that looks even remotely like a script tag. If you try to bind a string containing <script>alert(1)</script> to [innerHTML], Angular silently nukes it from orbit. This is why we rarely see XSS in Angular applications compared to the Wild West of raw React or jQuery.

But even the most vigilant guards have blind spots. In this case, the blind spot wasn't in the HTML specification, but in the quirky, legacy-ridden world of Scalable Vector Graphics (SVG). While Angular was busy meticulously guarding the front door (<script src="...">), it left the window (<svg><script href="...">) unlatched.

CVE-2026-22610 is a failure of categorization. It’s not that Angular couldn't sanitize the input; it’s that it didn't think it needed to. The framework looked at an SVG script tag with an href attribute, shrugged, and said, "That looks like a hyperlink to me." That assumption turned a benign property binding into a high-severity Remote Code Execution vector within the victim's browser context.

The Flaw: A Case of Mistaken Identity

To understand this bug, you have to understand Angular's DOM Security Schema. Angular classifies every DOM property into security contexts: HTML, STYLE, URL, and the most dangerous of all, RESOURCE_URL.

A URL context is for things like <a href="...">. You can put a link to https://google.com, but Angular will strip out javascript:alert(1).

A RESOURCE_URL context is for things that load executable code, like <script src="..."> or <iframe src="...">. Angular locks this down tight. You cannot bind a dynamic value to a RESOURCE_URL unless you explicitly tell Angular, "I trust this value with my life," using bypassSecurityTrustResourceUrl.

Here lies the logic error. Angular correctly identified that <script src="..."> requires RESOURCE_URL security. However, in the world of SVG, you don't always use src. Historically, you used xlink:href, and in modern SVG 2 specs, you just use href.

Angular's internal schema map missed this nuance. When the compiler encountered <script [attr.href]="..."> inside an SVG, it checked its list of "dangerous" attributes. Seeing href but failing to associate it with the script tag in an executable context, it downgraded the security requirement from RESOURCE_URL to plain old URL. This downgrade is fatal. It means the sanitizer allows data: URIs, which are perfectly valid for images or links but devastating when fed to a script tag.

The Code: The Smoking Gun

Let's look at the actual code in packages/core/src/sanitization/sanitization.ts. This is where the decision to sanitize—or not to sanitize—is made.

Before the Patch:

The function getUrlSanitizer determines which sanitizer function to use based on the tag and property name. Notice the omission in the HREF_RESOURCE_TAGS set.

// The set of tags where 'href' is considered a loadable resource
const HREF_RESOURCE_TAGS = new Set(['base', 'link']); 
 
export function getUrlSanitizer(tag: string, prop: string) {
  // If it's a 'src' attribute on a known tag, sanitize as Resource URL
  if (prop === 'src' && SRC_RESOURCE_TAGS.has(tag)) {
    return ɵɵsanitizeResourceUrl;
  }
  // If it's an 'href' attribute on 'base' or 'link', sanitize as Resource URL
  if (prop === 'href' && HREF_RESOURCE_TAGS.has(tag)) {
    return ɵɵsanitizeResourceUrl;
  }
  // Fallback: Just a regular URL (allows data: URIs!)
  return ɵɵsanitizeUrl;
}

Because script was missing from HREF_RESOURCE_TAGS, the function returned ɵɵsanitizeUrl. This sanitizer allows data: protocols because they are safe for <img> or <a> tags.

After the Patch (Commit 91dc91bae4):

The Angular team realized that script tags also use href (and xlink:href) to load code.

// 'script' is added to the naughty list
const HREF_RESOURCE_TAGS = new Set(['base', 'link', 'script']);
 
export function getUrlSanitizer(tag: string, prop: string) {
  const isResource =
    (prop === 'src' && SRC_RESOURCE_TAGS.has(tag)) ||
    (prop === 'href' && HREF_RESOURCE_TAGS.has(tag)) ||
    // Explicit check for the legacy SVG attribute
    (prop === 'xlink:href' && tag === 'script'); 
 
  return isResource ? ɵɵsanitizeResourceUrl : ɵɵsanitizeUrl;
}

By forcing ɵɵsanitizeResourceUrl, Angular now throws an error if a developer tries to bind a string to these attributes without explicit trust, effectively killing the XSS vector.

The Exploit: Weaponizing SVG

Exploiting this requires a specific but not uncommon scenario: an Angular application that renders SVGs using templates where attributes are bound to user-controllable data.

Imagine a dashboard application that allows users to customize their profile widget with an "Avatar" SVG. The application code might look like this:

<!-- component.html -->
<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  <!-- The developer thinks they are binding a link to a profile script -->
  <script [attr.href]="userProfileUrl"></script>
</svg>

The developer assumes userProfileUrl is just a URL. Angular cleans URLs, right?

The Attack Chain:

  1. Injection: The attacker updates their profile settings. In the userProfileUrl field, instead of https://example.com/profile.js, they input a Data URI payload: data:text/javascript,alert(document.cookie)

  2. Rendering: The Angular compiler sees [attr.href] on a script tag. It checks its schema. It thinks, "This is a safe URL context." It validates the protocol. data: is allowed in safe URL contexts (e.g., <img src="data:...">).

  3. Execution: Angular renders the DOM:

    <script href="data:text/javascript,alert(document.cookie)"></script>

    The browser's SVG engine parses this, sees a script element with an executable href, and immediately executes the JavaScript inside the Data URI.

Boom. You have XSS. No complex bypasses, no polyglots. Just a simple logic gap in the framework.

The Impact: Why This Matters

This vulnerability is particularly dangerous because it subverts the expectations of developers. Angular developers are trained to believe that the framework handles context-aware escaping automatically. They rely on the compiler to yell at them if they do something dangerous.

With a CVSS score of 8.5, the impact is high. Successful exploitation allows for:

  • Session Hijacking: Stealing JWTs or session cookies.
  • CSRF Bypass: Performing actions on behalf of the user without their consent.
  • Data Exfiltration: Reading sensitive data rendered on the page.

Furthermore, because this is a client-side template injection issue, it can often bypass server-side WAFs that aren't looking for standard XSS payloads but might miss a data:text/javascript string hidden inside a JSON API response.

The Fix: Closing the Window

The mitigation is straightforward: upgrade. The Angular team has backported fixes to all supported active versions.

Patched Versions:

  • Angular 19: 19.2.18
  • Angular 20: 20.3.16
  • Angular 21: 21.0.7

If you are stuck on an unpatched version (and shame on you, it's 2026), you have two temporary options:

  1. Content Security Policy (CSP): This is your best safety net. A strict CSP that disallows data: in the script-src directive will prevent the browser from executing the payload, even if Angular renders it.
    Content-Security-Policy: script-src 'self'; object-src 'none';
  2. Manual Audit: Grep your codebase for [attr.href] and [attr.xlink:href] inside <svg> blocks. If you find them on <script> tags, remove them or hardcode the values.

Official Patches

AngularOfficial fix commit on GitHub
AngularGitHub Security Advisory GHSA-jrmj-c5cx-3cw6

Fix Analysis (1)

Technical Appendix

CVSS Score
8.5/ 10
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
EPSS Probability
0.02%
Top 95% most exploited

Affected Systems

Angular Framework (@angular/core)

Affected Versions Detail

Product
Affected Versions
Fixed Version
@angular/core
Angular
< 19.2.1819.2.18
@angular/core
Angular
>= 20.0.0-next.0, < 20.3.1620.3.16
@angular/core
Angular
>= 21.0.0-next.0, < 21.0.721.0.7
@angular/core
Angular
>= 21.1.0-next.0, < 21.1.0-rc.021.1.0-rc.0
AttributeDetail
CWE IDCWE-79 (Improper Neutralization of Input During Web Page Generation)
CVSS v4.08.5 (High)
Attack VectorNetwork
Attack ComplexityLow
Privileges RequiredLow
ImpactHigh (Confidentiality, Integrity, Availability)
Exploit StatusPoC Available

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Cross-site Scripting

The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

Known Exploits & Detection

GitHubVulnerability scanner and PoC for Angular SVG XSS

Vulnerability Timeline

Fix committed to Angular repository
2026-01-06
Advisory published (GHSA-jrmj-c5cx-3cw6)
2026-01-10
NVD analysis completed
2026-01-13
Public technical analysis circulating
2026-01-28

References & Sources

  • [1]Angular Security Advisory
  • [2]CWE-79: Cross-site Scripting

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•13 minutes ago•CVE-2026-54249
6.8

CVE-2026-54249: Server-Side Request Forgery via Confused Deputy in Pydantic AI UI Adapters

A Server-Side Request Forgery (SSRF) / Confused Deputy vulnerability has been identified in Pydantic AI UI Adapters (such as VercelAIAdapter). Under certain conditions, a malicious client can supply manipulated message history with provider metadata that forces the server to resolve files within privileged cloud environments (AWS S3, Google Cloud Storage) or model providers. This occurs because the adapters deserialize client-provided metadata structures directly into UploadedFile instances without validation, which are subsequently fetched using high-privilege server credentials.

Alon Barad
Alon Barad
0 views•7 min read
•about 1 hour ago•GHSA-RM43-82J9-R4MJ
8.2

GHSA-RM43-82J9-R4MJ: Path Traversal (Arbitrary File Read) in atomic-agents-stack Dashboard

A path traversal vulnerability in the optional dashboard server of atomic-agents-stack before version 1.1.0 allows unauthenticated remote attackers to read arbitrary files from the host filesystem.

Amit Schendel
Amit Schendel
2 views•6 min read
•about 17 hours ago•CVE-2026-9318
5.4

CVE-2026-9318: Stored Cross-Site Scripting via HTML Export in Jazzband tablib

CVE-2026-9318 is a stored cross-site scripting (XSS) vulnerability affecting Jazzband tablib versions prior to 3.10.0. The flaw is located in the HTML export functionality of multi-sheet Databook objects. Due to raw f-string interpolation, unsanitized sheet titles containing malicious script tags are rendered directly as HTML, allowing arbitrary client-side code execution in a victim's browser.

Amit Schendel
Amit Schendel
5 views•8 min read
•about 18 hours ago•CVE-2026-54917
10.0

CVE-2026-54917: Cross-Bucket Path Traversal and Authorization Bypass in SeaweedFS S3 and Iceberg Gateways

CVE-2026-54917 is a critical path traversal and authorization bypass vulnerability affecting the S3 and Iceberg REST catalog gateways in SeaweedFS. By explicitly disabling canonical path cleaning in the gorilla/mux routing system, relative path segments such as '..' are allowed to bypass routing constraints and access control checks. When these paths are collapsed server-side by the backend filer, they resolve to folders outside the authorized bucket boundary, allowing unauthorized cross-bucket access.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 19 hours ago•GHSA-JWJP-4649-V8JP
7.5

GHSA-jwjp-4649-v8jp: Out-of-Bounds Read in SIPSorcery SCTP SACK Chunk Parsing

An out-of-bounds read vulnerability in the SCTP SACK chunk parser of SIPSorcery leads to Denial of Service (DoS) or silent internal state corruption due to lack of boundary validation on incoming chunk elements.

Amit Schendel
Amit Schendel
4 views•6 min read
•about 20 hours ago•GHSA-PFVM-W89X-94JW
7.5

GHSA-pfvm-w89x-94jw: Uncaught Exception in STUN Parser Causes Complete TurnServer Receive Loop Termination

An uncaught exception vulnerability exists in SIPSorcery's TurnServer component, where unauthenticated malformed UDP packets can crash the core UDP receive loop, resulting in a persistent Denial of Service.

Amit Schendel
Amit Schendel
7 views•6 min read