From e8a2c60b75354c1648a6b6a547896b7a9cfde98e Mon Sep 17 00:00:00 2001 From: Saadanjum0 <160885369+Saadanjum0@users.noreply.github.com> Date: Fri, 2 Oct 2026 12:41:22 +0500 Subject: [PATCH] fix(shared): escape attribute values in buildLucideSvg (#4940) * fix(shared): escape attribute values in buildLucideSvg Attribute values were interpolated into the SVG string as-is, so a value containing a double quote, ampersand or angle bracket (for example in a custom attribute or class name) produced malformed markup. * Use replace(/x/g) instead of replaceAll for broader TS lib compat lucide-react-native's tsconfig doesn't include the ES2021 lib that replaceAll requires, failing typecheck. A global regex replace is functionally identical here and works under any target. * Escape the full set of relevant HTML entities in attribute values Also escape > and ' per review feedback, not just & " <. * Apply suggestion from @karsa-mistmere --------- Co-authored-by: Karsa --- packages/shared/src/build/buildLucideSvg.ts | 13 ++++++++++++- packages/shared/tests/buildLucideSvg.spec.ts | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/shared/tests/buildLucideSvg.spec.ts diff --git a/packages/shared/src/build/buildLucideSvg.ts b/packages/shared/src/build/buildLucideSvg.ts index f2bc8b8fc..fa19192ca 100644 --- a/packages/shared/src/build/buildLucideSvg.ts +++ b/packages/shared/src/build/buildLucideSvg.ts @@ -1,10 +1,21 @@ import buildLucideIconNode from './buildLucideIconNode'; import type { LucideBuildParams, LucideIconData, LucideIconNode } from './types'; +const entities = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', +} as const; + +const escapeAttribute = (value: string) => + value.replace(/[&<>"']/g, (char) => entities[char as keyof typeof entities]); + const buildDomNode = ([tagName, attributes, children = []]: LucideIconNode): string => `<${tagName} ${Object.entries(attributes) .filter(([, value]) => value !== undefined && value !== null) - .map(([attrName, value]) => `${attrName}="${String(value)}"`) + .map(([attrName, value]) => `${attrName}="${escapeAttribute(String(value))}"`) .join(' ')}>${children?.map((child) => buildDomNode(child)).join('')}`; /** diff --git a/packages/shared/tests/buildLucideSvg.spec.ts b/packages/shared/tests/buildLucideSvg.spec.ts new file mode 100644 index 000000000..896a7464e --- /dev/null +++ b/packages/shared/tests/buildLucideSvg.spec.ts @@ -0,0 +1,14 @@ +import { describe, it, expect } from 'vitest'; +import buildLucideSvg from '../src/build/buildLucideSvg'; + +const icon = { name: 'dot', size: 24, node: [['circle', { cx: 12, cy: 12, r: 1 }]] } as const; + +describe('buildLucideSvg', () => { + it('should escape special characters in attribute values', () => { + const svg = buildLucideSvg(icon as any, { + attributes: { 'data-label': 'a\'s "quoted" & c' }, + }); + + expect(svg).toContain('data-label="a's "quoted" <b> & c"'); + }); +});