Summary
The ZAC network visualizer renders some node labels and hover tooltips by writing controller entity data straight into the DOM, without HTML-encoding it. An entity whose name or role attributes contain HTML/script markup is rendered as markup, resulting in stored cross-site scripting in the console when an operator opens the visualizer.
Affected Component
- Package:
openziti/ziti-console(Ziti Admin Console) and the@openziti/ziti-console-libshared library - File:
projects/ziti-console-lib/src/lib/features/visualizer/network-visualizer/network-visualizer.component.ts - Sinks: node label rendering via d3
.html(), and the tree hover tooltip viaelement.innerHTML
Vulnerability Class
- Primary: CWE-79 — Improper Neutralization of Input During Web Page Generation (Cross-site Scripting), stored/DOM-based
Attacker Model
Requires an actor able to create or name Ziti entities (identities, services, routers) or set their role attributes. This is not an unauthenticated remote attack — the payload is stored in entity data and executes later, in the browser session of an operator who views it.
Preconditions
- An entity name or role attribute contains HTML/script markup.
- An operator opens the network visualizer and the affected node label/tooltip is rendered.
Root Cause
The visualizer writes entity data into the DOM through d3's .html() and element.innerHTML, which bypass Angular's built-in template sanitization. Controller-supplied names and attributes were interpolated into that markup without encoding, so any markup they contain is parsed and executed rather than displayed as text. (The identity-service-path tooltip already HTML-encodes its values and is not affected.)
Impact
Stored XSS executing in the console's origin, in the session of the viewing operator. Conservative severity reflects the authenticated precondition and the required operator interaction.
- CVSS v3.1: 5.4 (Medium)
- Vector:
AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Not impacted: no unauthenticated access, no RCE, no controller auth bypass; exploitation depends on an operator opening the visualizer.
Package
openziti/ziti-console (app-ziti-console) and @openziti/ziti-console-lib
Affected Versions
- app-ziti-console
< 4.5.4 - ziti-console-lib
< 1.5.4
Patched Versions
- app-ziti-console
4.5.4 - ziti-console-lib
1.5.4
Remediation
Upgrade to the patched versions. The fix HTML-encodes entity-supplied strings before inserting them at these sinks (via a shared escapeHtml helper) so they always render as text.
References
- GHSA: https://github.com/openziti/ziti-console/security/advisories/GHSA-rf2c-2p5r-7g29
- CVE: (pending)
Credits
Reported by sajdakabir.