Skip to content

fix(Gradient): escape colorStop colors in SVG export (backport GHSA-w22m to 6.x)#11032

Open
greymoth-jp wants to merge 1 commit into
fabricjs:6.xfrom
greymoth-jp:fix/gradient-colorstop-svg-escape-6x
Open

fix(Gradient): escape colorStop colors in SVG export (backport GHSA-w22m to 6.x)#11032
greymoth-jp wants to merge 1 commit into
fabricjs:6.xfrom
greymoth-jp:fix/gradient-colorstop-svg-escape-6x

Conversation

@greymoth-jp

Copy link
Copy Markdown

The 6.x line is missing the gradient colorStop escaping that shipped on the active major in v7.4.0 for GHSA-w22m-hvvm-xmwx. On 6.9.1, Gradient.toSVG() inlines each colorStop color straight into the style="stop-color:..." attribute with no escaping, so a crafted color breaks out of the attribute and injects arbitrary SVG. This is reachable whenever a gradient comes from untrusted input (e.g. loadFromJSON) and the canvas is later serialized with toSVG().

Repro on 6.9.1:

const g = new Gradient({
  type: 'linear',
  colorStops: [{ offset: 0, color: 'red"><img src=x onerror=alert(1)>' }],
});
g.toSVG(new Rect({ width: 100, height: 100, fill: g }));
// <stop offset="0%" style="stop-color:red"><img src=x onerror=alert(1)>;"/>

This backports the v7.4.0 fix: a value that is not a safe SVG style token is normalized through Color(...).toRgba(), and the result is passed through escapeXml for the attribute context. Because style="stop-color:..." is a CSS declaration, XML-escaping alone is not enough, hence the normalization step. Safe values (currentColor, var(--x), rgb(...), named colors) are left as-is, so existing output is preserved.

escapeXml already exists on 6.x; the only new file is the isSafeSvgStyleValue helper, copied from the v7 implementation. Added unit tests covering the HTML, CSS-declaration and url payloads plus the safe-value passthrough.

Oracle: GHSA-w22m-hvvm-xmwx, fixed on the active major in v7.4.0.

Backport of the v7.4.0 fix for GHSA-w22m-hvvm-xmwx. On 6.x, Gradient.toSVG
inlines each colorStop color into the style="stop-color:..." attribute
without escaping, so a crafted color can break out of the attribute and
inject SVG markup. Normalize values that are not safe SVG style tokens
through Color(...).toRgba() and escape the result, matching the active
major. Safe values are preserved.
@codesandbox

codesandbox Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@greymoth-jp

Copy link
Copy Markdown
Author

Closing this since CI is red and I can't verify it properly. I'd rather not leave a broken PR in your queue. Sorry for the noise.

@greymoth-jp greymoth-jp closed this Jul 4, 2026
@asturur asturur reopened this Jul 9, 2026
@asturur

asturur commented Jul 9, 2026

Copy link
Copy Markdown
Member

No worries i ll get here. I have just to be sure things work properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants