Skip to content

CVE-2026-27013: Verified Repro With Script Download

CVE-2026-27013: Fabric.js: Stored XSS via SVG Export

CVE-2026-27013 is verified against fabric · npm. Affected versions: < 7.2.0. Fixed in 7.2.0. Vulnerability class: XSS. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00105.

REPRO-2026-00105 fabric · npm XSS Feb 19, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.6
Reproduced in
16m 24s
Tool calls
97
Spend
$0.30
01 · Overview

What Is CVE-2026-27013?

CVE-2026-27013 (GHSA-hfvx-25r5-qc3w) is a high-severity stored cross-site scripting (XSS) vulnerability in Fabric.js's SVG export functionality, present in versions before 7.2.0. Pruva reproduced it (reproduction REPRO-2026-00105).

02 · Severity & CVSS

CVE-2026-27013 Severity & CVSS Score

CVE-2026-27013 is rated high severity, with a CVSS base score of 7.6 out of 10.

HIGH threat level
7.6 / 10 CVSS base

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected fabric Versions

fabric · npm versions < 7.2.0 are affected.

How to Reproduce CVE-2026-27013

$ pruva-verify REPRO-2026-00105
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00105/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-27013

Reproduced by Pruva's autonomous agents — 97 tool calls over 16 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 280 events · 97 tool calls · 16 min
16 minDuration
97Tool calls
59Reasoning steps
280Events
2Dead-ends
Agent activity over 16 min
Support
21
Repro
116
Variant
139
0:0016:24

Root Cause and Exploit Chain for CVE-2026-27013

Summary

Fabric.js versions prior to 7.2.0 contain a stored Cross-Site Scripting (XSS) vulnerability in their SVG export functionality. When user-controlled JSON is loaded via loadFromJSON() and later exported via toSVG(), the id property and other user-controlled string values are interpolated directly into SVG attribute markup without XML escaping. This allows an attacker to break out of XML attributes and inject arbitrary SVG elements including event handlers, leading to stored XSS.

Impact

  • Package: fabric (npm)
  • Affected Versions: < 7.2.0
  • Fixed Version: 7.2.0
  • CVE: CVE-2026-27013
  • GHSA: GHSA-hfvx-25r5-qc3w
  • CVSS Score: 7.6 (HIGH)
  • CWEs: CWE-79 (XSS), CWE-116 (Improper Encoding or Escaping)
Risk and Consequences

Any application that:

  1. Accepts user-supplied JSON (via loadFromJSON(), collaborative sharing, import features, CMS plugins)
  2. Renders the toSVG() output in a browser context (SVG preview, export download, email templates, embeds)

...is vulnerable to stored XSS. An attacker can execute arbitrary JavaScript in the victim's browser session. Real-world attack scenarios include:

  • 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

Root Cause

The vulnerability exists because fabric.js fails to apply XML escaping to user-controlled string values that are interpolated into SVG attribute markup. While escapeXml() is correctly applied to text content during SVG export (in src/shapes/Text/TextSVGExportMixin.ts:186), it is NOT applied to other user-controlled string values.

Vulnerable Code Location

File: src/shapes/Object/FabricObjectSVGExportMixin.ts
Method: getSvgCommons() (line 85-97)

getSvgCommons(
  this: FabricObjectSVGExportMixin & FabricObject & { id?: string },
) {
  return [
    this.id ? `id="${this.id}" ` : '',  // <-- UNESCAPED, user-controlled
    this.clipPath
      ? `clip-path="url(#${...})" `
      : '',
  ].join('');
}

This method is called in _createBaseSVGMarkup() which wraps every object's SVG output in a <g> element. Since all fabric object types (Rect, Circle, Path, Text, Image, Group, etc.) inherit this mixin, the id injection vector applies to all object types.

Deserialization Path (No Sanitization)

loadFromJSON() (src/canvas/StaticCanvas.ts:1229) → enlivenObjects()_fromObject() (src/shapes/Object/Object.ts:1902) → constructor → _setOptions() (src/CommonMethods.ts:9)

There is no allowlist or sanitization - any property in the JSON, including id, is set verbatim on the fabric object.

Fix Commit

The security fix was applied in commit: https://github.com/fabricjs/fabric.js/commit/7e1a122defd8feefe4eb7eaf0c180d7b0aeb6fee

The fix adds escapeXml() calls to all affected locations:

  • src/shapes/Object/FabricObjectSVGExportMixin.ts: Escapes this.id
  • src/shapes/Image.ts: Escapes getSvgSrc() in xlink:href
  • src/Pattern/Pattern.ts: Escapes pattern id and sourceToString()
  • src/gradient/Gradient.ts: Escapes gradient id
  • src/Shadow.ts: Escapes shadow id

Reproduction Steps

Run the reproduction script:

./repro/reproduction_steps.sh
What the Script Does
  1. Clones fabric.js repository at the vulnerable version (7.1.0)
  2. Builds the project using npm
  3. Creates a Node.js test script that:
    • Creates a Rect object with a malicious id property containing XSS payload: ""><script>alert(1)</script><rect id="
    • Exports the object to SVG using toSVG()
    • Checks if the payload is escaped or unescaped in the output
  4. Returns exit code 0 if vulnerable, 1 if patched
Expected Evidence of Reproduction

When vulnerable, the generated SVG contains the unescaped payload:

<g transform="matrix(1 0 0 1 0 0)" id=""><script>alert(1)</script><rect id=""  >

The malicious id value breaks out of the id attribute and injects a <script> tag directly into the SVG markup.

Evidence

Reproduction Log
  • Location: logs/reproduction.log
  • Key Excerpt:
    ❌ VULNERABILITY CONFIRMED: Payload is NOT escaped in SVG output!
    The id attribute allows XSS injection via SVG export.
    
Generated Vulnerable SVG Output
<g transform="matrix(1 0 0 1 0 0)" id=""><script>alert(1)</script><rect id=""  >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;"  x="-50" y="-50" rx="0" ry="0" width="100" height="100" />
</g>
Environment Details
  • Node.js Version: 22.22.0
  • Fabric.js Version: 7.1.0 (vulnerable)
  • OS: Linux

Recommendations / Next Steps

Immediate Actions
  1. Upgrade to fabric.js 7.2.0 or newer immediately
  2. Validate any stored JSON data that may have been created by untrusted users
  3. Sanitize SVG output if you cannot upgrade immediately (apply XML escaping to all interpolated values)
Testing Recommendations
  • Add regression tests that verify XML escaping for all user-controlled properties
  • Test SVG export with payloads containing: ", <, >, &, ', and JavaScript event handlers
  • Consider using a content security policy (CSP) as defense-in-depth
Additional Affected Files (Per Ticket Analysis)
File Issue Method
src/shapes/Image.ts Unescaped getSvgSrc() in xlink:href _toSVG()
src/Pattern/Pattern.ts Unescaped sourceToString() in xlink:href; unescaped id toSVG()
src/gradient/Gradient.ts User-supplied id prefix interpolated unescaped toSVG()

Additional Notes

Idempotency Confirmation

The reproduction script has been run twice consecutively with consistent results:

  • Run 1: Vulnerability confirmed (exit code 0)
  • Run 2: Vulnerability confirmed (exit code 0)
Edge Cases
  • The vulnerability affects all fabric object types (Rect, Circle, Path, Text, Image, Group, etc.) through the shared getSvgCommons() mixin
  • Multiple attack vectors exist: id property, Image src, Pattern source, Gradient id
  • The payload needs to break out of XML attribute context (") and inject new elements
Limitations

This reproduction focuses on the primary id property injection vector. Other vectors (Image src, Pattern source, Gradient id) are also exploitable per the ticket analysis but were not explicitly tested in this reproduction script.

CVE-2026-27013 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:003:17
0:00
session startedaccounts/fireworks/models/kimi-k2p5 · ghsa-hfvx-25r5-qc3w · ghsa-hfv
0:07
0:22
0:58
web search
1:00
1:03
web search
1:06
1:09
web search
1:28
1:28
extract_facts
no facts extracted
2:13
2:13
2:13
supportrepro
3:07
3:07
3:07
3:09
3:09
3:09
3:13
3:13
3:16
web search
3:17

Artifacts and Evidence for CVE-2026-27013

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-27013

Upgrade fabric · npm to 7.2.0 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-27013 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-27013

How does the CVE-2026-27013 stored-XSS attack work?

An attacker supplies user-controlled JSON (e.g. via a shared canvas or import feature) whose id (or other string) property contains XML-breaking content. When that JSON is loaded via loadFromJSON() and later exported with toSVG(), the value is interpolated directly into SVG attribute markup without XML escaping, letting the attacker break out of the attribute and inject arbitrary SVG elements or event handlers that execute when the exported SVG is rendered in a browser.

Which fabric.js versions are affected by CVE-2026-27013, and where is it fixed?

Affects fabric (npm) < 7.2.0; fixed in 7.2.0.

How severe is CVE-2026-27013?

High severity, CVSS 7.6 (CWE-79 Cross-Site Scripting, CWE-116 Improper Encoding or Escaping).

How can I reproduce CVE-2026-27013?

Download the verified script and run it in an isolated environment against fabric.js < 7.2.0; it loads a crafted JSON object (with an XML-breaking id) via loadFromJSON(), exports it with toSVG(), and confirms the unescaped payload breaks out of the SVG attribute in the rendered output.
11 · References

References for CVE-2026-27013

Authoritative sources for CVE-2026-27013 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.