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.

Supporting Links