Skip to content

Commit 740c3d6

Browse files
committed
fix: sanitise markup
1 parent 432120d commit 740c3d6

File tree

1 file changed

+17
-4
lines changed

1 file changed

+17
-4
lines changed

app/utils/charts.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,14 @@ function pickValue<T>(values: NonEmptyReadonlyArray<T>, generateRandomNumber: ()
828828
return selectedValue
829829
}
830830

831+
function escapeSvgAttribute(value: string): string {
832+
return value
833+
.replace(/&/g, '&amp;')
834+
.replace(/"/g, '&quot;')
835+
.replace(/</g, '&lt;')
836+
.replace(/>/g, '&gt;')
837+
}
838+
831839
function createLineElement(
832840
x1: number,
833841
y1: number,
@@ -837,7 +845,8 @@ function createLineElement(
837845
strokeWidth: number,
838846
opacity: number,
839847
): string {
840-
return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${strokeWidth}" opacity="${opacity}" shape-rendering="crispEdges" stroke-linecap="round" stroke-linejoin="round" />`
848+
const safeStroke = escapeSvgAttribute(stroke)
849+
return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${safeStroke}" stroke-width="${strokeWidth}" opacity="${opacity}" shape-rendering="crispEdges" stroke-linecap="round" stroke-linejoin="round" />`
841850
}
842851

843852
function createCircleElement(
@@ -847,7 +856,8 @@ function createCircleElement(
847856
fill: string,
848857
opacity: number,
849858
): string {
850-
return `<circle cx="${centerX}" cy="${centerY}" r="${radius}" fill="${fill}" opacity="${opacity}" />`
859+
const safeFill = escapeSvgAttribute(fill)
860+
return `<circle cx="${centerX}" cy="${centerY}" r="${radius}" fill="${safeFill}" opacity="${opacity}" />`
851861
}
852862

853863
function createPathElement(
@@ -857,7 +867,9 @@ function createPathElement(
857867
strokeWidth: number,
858868
opacity: number,
859869
): string {
860-
return `<path d="${pathData}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}" opacity="${opacity}" stroke-linecap="round" stroke-linejoin="round" />`
870+
const safeFill = escapeSvgAttribute(fill)
871+
const safeStroke = escapeSvgAttribute(stroke)
872+
return `<path d="${pathData}" fill="${safeFill}" stroke="${safeStroke}" stroke-width="${strokeWidth}" opacity="${opacity}" stroke-linecap="round" stroke-linejoin="round" />`
861873
}
862874

863875
function toNonEmptyReadonlyArray<T>(values: readonly T[]): NonEmptyReadonlyArray<T> {
@@ -1025,7 +1037,8 @@ export function createSeededSvgPattern(
10251037
}
10261038

10271039
if (backgroundColor !== 'transparent') {
1028-
contentMarkup = `<rect x="0" y="0" width="${tileSize}" height="${tileSize}" fill="${backgroundColor}" />${contentMarkup}`
1040+
const safeBackgroundColor = escapeSvgAttribute(backgroundColor)
1041+
contentMarkup = `<rect x="0" y="0" width="${tileSize}" height="${tileSize}" fill="${safeBackgroundColor}" />${contentMarkup}`
10291042
}
10301043

10311044
return {

0 commit comments

Comments
 (0)