Plotly.js SVG XSS and CSS Injection
Summary
Plotly.js returned malformed SVG markup from user-controlled plot fields. The rendered SVG allowed an attacker to inject executable behavior through link attributes and to trigger cross-domain resource loads through CSS.
Affected Surface
- Product: Plot.ly / Plotly.js
- Component: SVG text rendering and sanitization
- Affected versions: Plotly.js before 1.16.0
- Vulnerability classes: stored XSS, CSS injection, external resource injection
Impact
An attacker who could create or edit a plot could inject malicious SVG content that executed JavaScript in the Plot.ly web application when another user interacted with the plot. A second issue allowed remote image/resource loads, which could disclose viewer metadata and support user tracking.
Root Cause
SVG link handling accepted unsafe attribute construction. Production code preserved user-controlled attribute fragments while building xlink:href markup, allowing attacker-controlled attributes to escape the intended sanitized form.
The CSS/resource issue came from allowing style-controlled external resource loads inside rendered SVG content.
Evidence
Testing showed that crafted plot title fields could produce SVG anchor markup with attacker-controlled behavior. Follow-up testing showed that style attributes could load remote resources from a viewer’s browser.
The vulnerable code path was traced to svg_text_utils.js in Plotly.js. The issue was already patched on the main branch but had not yet reached production when the report was validated.
Remediation
- Upgrade Plotly.js to 1.16.0 or later.
- Backport the sanitization fix to CDN-hosted versions.
- Build SVG elements through safe DOM APIs instead of concatenating attribute strings.
- Restrict protocols and remove user-controlled event, style, and external-resource behavior.
- Add regression tests for SVG anchor attributes and style-based resource loading.
Timeline
- 2016-07-24: Report sent
- 2016-07-25: Team responded
- 2016-07-25 to 2016-08-08: Fixes rolled out to Plotly.js and customers
- 2016-08-09: Public disclosure
Advisory
Plotly.js before 1.16.0 was vulnerable to malformed SVG output that enabled XSS and CSS/resource injection. Plot.ly published a related advisory at the time of disclosure.