Vulnerability DatabaseGHSA-ffj9-42qx-f38h

GHSA-ffj9-42qx-f38h: 
JavaScript vulnerability analysis and mitigation

A Cross-Site Scripting (XSS) vulnerability was identified in @angular/upgrade when using downgradeComponent() in hybrid Angular / AngularJS applications.

Technical Description

When an Angular component is downgraded via downgradeComponent() for use inside an AngularJS (1.x) template, DowngradeComponentAdapter.compileContents() prepares the element's child DOM nodes for content projection (<ng-content>) by passing them to the AngularJS $compile() service. Previously, compileContents() read and compiled the live child nodes of the host element (this.element.contents()) at the time the downgraded Angular component instance was created, rather than capturing the original static template child nodes prior to linking. Although the directive registered by downgradeComponent() specifies terminal: true, it uses the default AngularJS directive priority (0). Consequently, other priority-0 AngularJS directives placed on the same host element (such as ng-bind, ng-bind-html, or ng-transclude) still execute. When a co-located directive writes user-bound data or inserts already-linked transcluded DOM nodes into the downgraded host element before compileContents() runs (such as during asynchronous downgradeModule() bootstrapping or when ngTransclude's post-link executes prior to the downgraded directive's post-link), compileContents() passes that dynamic content to $compile(). Any AngularJS interpolation ({{ ... }}) or directive syntax (including class-based directives like class="ng-bind: ..." that survive $sanitize in ng-bind-html) present in the data is compiled and executed as an AngularJS template expression.

Impact

Successful exploitation allows an attacker who controls data rendered within the downgraded element to execute arbitrary JavaScript in the victim user's browser within the context of the application's origin (Cross-Site Scripting).

  • Pure Angular Applications Unaffected: Standard Angular applications that do not run a hybrid AngularJS setup via @angular/upgrade (downgradeComponent()) are not vulnerable.

Attack Preconditions

An application is affected if the following conditions are met:

  • Hybrid Application: The application uses @angular/upgrade (downgradeComponent()) to embed Angular components inside AngularJS templates.
  • Co-located Host Directive: An AngularJS directive that populates the element's DOM contents during linking (such as ng-bind, ng-bind-html, or ng-transclude) is placed directly on a downgraded component's host element and runs before downgradeComponent() compiles the element's contents.
  • User-Controlled Data: The content written or transcluded into the downgraded host element includes untrusted user input.

Exploit Payload Example

<user-badge ng-bind="$ctrl.user.name"></user-badge>

If $ctrl.user.name contains an AngularJS template expression (e.g., {{constructor.constructor('alert(document.domain)')()}}), the co-located directive writes the value into <user-badge> during linking, and downgradeComponent() subsequently passes the host element's contents to $compile(), evaluating the expression.

Patches

The issue is resolved by capturing a clone of the downgraded element's static template child nodes inside the directive's controller phase (prior to any directive preLink or postLink execution) and only passing those static template nodes to $compile(). Any DOM nodes dynamically inserted at link time when the original template was empty are projected directly without invoking $compile().

  • 22.2.4
  • 21.2.26
  • 20.3.35

Workarounds

If you cannot immediately upgrade to a patched version, do not place ng-bind, ng-bind-html, or ng-transclude directly on a downgraded component's host element.

  • Instead of binding on the downgraded host element (<user-badge ng-bind="$ctrl.user.name"></user-badge>), move the binding onto an inner child element (<user-badge><span ng-bind="$ctrl.user.name"></span></user-badge>) or pass the value via an Angular @Input() property binding (<user-badge [name]="$ctrl.user.name"></user-badge>).
  • Instead of placing ng-transclude directly on the downgraded host element (<app-card ng-transclude></app-card>), place ng-transclude on a wrapper child element inside the downgraded component (<app-card><div ng-transclude></div></app-card>).

References


Source: NVD

Related JavaScript vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-cr4j-qhrf-249wHIGH7.5
  • JavaScript logoJavaScript
  • @logto/tunnel
NoYesNov 09, 2026
GHSA-2pq4-jqvf-f7qjMEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-c5hj-jm58-pxh9MEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-3xj6-982x-2r3gMEDIUM6.5
  • JavaScript logoJavaScript
  • @logto/core
NoYesNov 09, 2026
GHSA-ffj9-42qx-f38hMEDIUM6.3
  • JavaScript logoJavaScript
  • @angular/upgrade
NoYesNov 09, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management