GitHub Advisoryadvisory · npm

GHSA-hfvx-25r5-qc3w Fabric.js Affected by Stored XSS via SVG Export

HIGH Published 2026-02-18 Modified 2026-02-19 Official page ↗
Aliases
CVE-2026-27013
Ecosystem
npm
Packages
fabric
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L
Weaknesses
CWE-116, CWE-79
Reviewed
2026-02-18

Affected packages

• npm fabric: < 7.2.0 → fixed in 7.2.0

Description

fabric.js applies `escapeXml()` to text content during SVG export (`src/shapes/Text/TextSVGExportMixin.ts:186`) but fails to apply it to other user-controlled string values that are interpolated into SVG attribute markup. When attacker-controlled JSON is loaded via `loadFromJSON()` and later exported via `toSVG()`, the unescaped values break out of XML attributes and inject arbitrary SVG elements including event handlers. Deserialization Path (no sanitization) `loadFromJSON()` (`src/canvas/StaticCanvas.ts:1229`) calls `enlivenObjects()` which calls `_fromObject()` (`src/shapes/Object/Object.ts:1902`). `_fromObject` passes all deserialized properties to the shape constructor via `new this(enlivedObjectOptions)`. The constructor ultimately calls `_setOptions()` (`src/CommonMethods.ts:9`) which iterates over every property and assigns it to the object via `this.set(prop, options[prop])`. There is no allowlist or sanitization - any property in the JSON, including `id`, is set verbatim on the fabric object. --- Finding 1: XSS via `id` Property Injection The `id` property from deserialized JSON is interpolated directly into SVG attribute strings without escaping. Vulnerable code (`src/shapes/Object/FabricObjectSVGExportMixin.ts`, line 89, `getSvgCommons()`): ```typescript getSvgCommons( this: FabricObjectSVGExportMixin & FabricObject & { id?: string }, ) { return this.id ? `id="${this.id}" ` : '', // ` element. Every fabric object type (Rect, Circle, Path, Text, Image, Group, etc.) inherits this mixin, so the `id` injection vector applies to all object types. Contrast with text content, which IS escaped: ```typescript // src/shapes/Text/TextSVGExportMixin.ts:186 return `${escapeXml(char)}`; ``` The inconsistency shows that the intention was to prevent injection but was missed w attribute contexts. --- Finding 2: XSS via Image `src` / `xlink:href` Injection Image source URLs are interpolated raw into `xlink:href` in `_toSVG()`. Vulnerable code (`src/shapes/Image.ts`, line 404, `_toSVG()`): ```typescript imageMarkup.push( '\t` // ` ``` --- Finding 4: Gradient `id` Partial Injection (lower Severity) Vulnerable code (`src/gradient/Gradient.ts`, line 212, `toSVG()`): ```typescript `id="SVGID_${this.id}"` // ` suffix appended after it. --- Impact Any application that: 1. Accepts user-supplied JSON (via `loadFromJSON()`, collaborative sharing, import features, CMS plugins), AND 2. Renders the `toSVG()` output in a browser context (SVG preview, export download rendered in-page, email template, embed) ...is vulnerable to stored XSS. An attacker can execute arbitrary JavaScript in the victim's browser session. Real-world attack scenarios: • Collaborative design tools (Canva-like apps) where users share canvas state as JSON • CMS or e-commerce platforms with fabric.js-based editors that store/render designs • Any export-to-SVG workflow where the SVG is later displayed in a browser --- Remediation Update to [fabric.js 7.2.0 or newer version. --- Confirmed Affected Files | File | Issue | Method | Exploitable | |---|---|---|---| | `src/shapes/Object/FabricObjectSVGExportMixin.ts` | Unescaped `this.id` in attribute | `getSvgCommons()` | Yes - primary vector, all object types | | `src/shapes/Image.ts` | Unescaped `getSvgSrc()` in `xlink:href` | `_toSVG()` | Yes | | `src/Pattern/Pattern.ts` | Unescaped `sourceToString()` in `xlink:href`; unescaped `id` in attribute | `toSVG()` | Yes | | `src/gradient/Gradient.ts` | User-supplied `id` prefix interpolated unescaped | `toSVG()` | Yes (partial - uid suffix appended) |

Related

Alias · CVE (1)

  • CVE-2026-27013 Fabric.js is a Javascript HTML5 canvas library. vulnerability

Weakness · CWE (2)

  • CWE-116 Improper Encoding or Escaping of Output weakness
  • CWE-79 Improper Neutralization of Input During Web Page Generation weakness

References