From 8090580c677408f58e6601fc3b4187a4cd57d02f Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 22:27:21 +0530 Subject: [PATCH 1/8] test: Handle missing bindFunctions --- cypress/platform/viewer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cypress/platform/viewer.js b/cypress/platform/viewer.js index e120469fe..7ff95e163 100644 --- a/cypress/platform/viewer.js +++ b/cypress/platform/viewer.js @@ -182,7 +182,7 @@ const contentLoadedApi = async function () { for (let i = 0; i < numCodes; i++) { const { svg, bindFunctions } = await mermaid.render('newid' + i, graphObj.code[i], divs[i]); div.innerHTML = svg; - bindFunctions(div); + bindFunctions?.(div); } } else { const div = document.createElement('div'); @@ -194,7 +194,7 @@ const contentLoadedApi = async function () { const { svg, bindFunctions } = await mermaid.render('newid', graphObj.code, div); div.innerHTML = svg; console.log(div.innerHTML); - bindFunctions(div); + bindFunctions?.(div); } } }; From 526b35c602129ede7490d322bcc3d363b7f35909 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 22:30:45 +0530 Subject: [PATCH 2/8] test: Architecture XSS --- cypress/helpers/util.ts | 2 +- cypress/integration/other/xss.spec.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cypress/helpers/util.ts b/cypress/helpers/util.ts index 81b7036af..a1291fa30 100644 --- a/cypress/helpers/util.ts +++ b/cypress/helpers/util.ts @@ -14,7 +14,7 @@ interface CodeObject { mermaid: CypressMermaidConfig; } -const utf8ToB64 = (str: string): string => { +export const utf8ToB64 = (str: string): string => { return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64'); }; diff --git a/cypress/integration/other/xss.spec.js b/cypress/integration/other/xss.spec.js index 1e51d2f23..b2f629935 100644 --- a/cypress/integration/other/xss.spec.js +++ b/cypress/integration/other/xss.spec.js @@ -1,4 +1,4 @@ -import { mermaidUrl } from '../../helpers/util.ts'; +import { imgSnapshotTest, mermaidUrl, utf8ToB64 } from '../../helpers/util.ts'; describe('XSS', () => { it('should handle xss in tags', () => { const str = @@ -141,4 +141,15 @@ describe('XSS', () => { cy.wait(1000); cy.get('#the-malware').should('not.exist'); }); + + it('should sanitize icon labels in architecture diagrams', () => { + const str = JSON.stringify({ + code: `architecture-beta + group api(cloud)[API] + service db "" [Database] in api`, + }); + imgSnapshotTest(utf8ToB64(str), {}, true); + cy.wait(1000); + cy.get('#the-malware').should('not.exist'); + }); }); From c61a431e2d663ead577cb24fa3c9a6bd846d9061 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 22:32:38 +0530 Subject: [PATCH 3/8] fix: Sanitize iconText --- packages/mermaid/src/diagrams/architecture/svgDraw.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/diagrams/architecture/svgDraw.ts b/packages/mermaid/src/diagrams/architecture/svgDraw.ts index f384defd8..6e470caa2 100644 --- a/packages/mermaid/src/diagrams/architecture/svgDraw.ts +++ b/packages/mermaid/src/diagrams/architecture/svgDraw.ts @@ -3,6 +3,7 @@ import { getConfig } from '../../diagram-api/diagramAPI.js'; import { createText } from '../../rendering-util/createText.js'; import { getIconSVG } from '../../rendering-util/icons.js'; import type { D3Element } from '../../types.js'; +import { sanitizeText } from '../common/common.js'; import type { ArchitectureDB } from './architectureDb.js'; import { architectureIcons } from './architectureIcons.js'; import { @@ -271,6 +272,7 @@ export const drawServices = async function ( elem: D3Element, services: ArchitectureService[] ): Promise { + const config = getConfig(); for (const service of services) { const serviceElem = elem.append('g'); const iconSize = db.getConfigField('iconSize'); @@ -285,7 +287,7 @@ export const drawServices = async function ( width: iconSize * 1.5, classes: 'architecture-service-label', }, - getConfig() + config ); textElem @@ -320,7 +322,7 @@ export const drawServices = async function ( .attr('class', 'node-icon-text') .attr('style', `height: ${iconSize}px;`) .append('div') - .html(service.iconText); + .html(sanitizeText(service.iconText, config)); const fontSize = parseInt( window From ecf7ab435542107579fadcba8f594cc71edd37d2 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 22:33:05 +0530 Subject: [PATCH 4/8] fix: Sanitize getIconSVG --- packages/mermaid/src/rendering-util/icons.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/rendering-util/icons.ts b/packages/mermaid/src/rendering-util/icons.ts index 50b1bbeb9..65f35bc62 100644 --- a/packages/mermaid/src/rendering-util/icons.ts +++ b/packages/mermaid/src/rendering-util/icons.ts @@ -1,7 +1,9 @@ -import { log } from '../logger.js'; import type { ExtendedIconifyIcon, IconifyIcon, IconifyJSON } from '@iconify/types'; import type { IconifyIconCustomisations } from '@iconify/utils'; import { getIconData, iconToHTML, iconToSVG, replaceIDs, stringToIcon } from '@iconify/utils'; +import { getConfig } from '../config.js'; +import { sanitizeText } from '../diagrams/common/common.js'; +import { log } from '../logger.js'; interface AsyncIconLoader { name: string; @@ -100,5 +102,5 @@ export const getIconSVG = async ( ...renderData.attributes, ...extraAttributes, }); - return svg; + return sanitizeText(svg, getConfig()); }; From 12e01bdb5cacf3569133979a5a4f1d8973e9aec1 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 22:41:10 +0530 Subject: [PATCH 5/8] docs: Add changeset --- .changeset/good-weeks-tickle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/good-weeks-tickle.md diff --git a/.changeset/good-weeks-tickle.md b/.changeset/good-weeks-tickle.md new file mode 100644 index 000000000..723e5932b --- /dev/null +++ b/.changeset/good-weeks-tickle.md @@ -0,0 +1,5 @@ +--- +'mermaid': patch +--- + +fix: sanitize icon labels and icon SVGs From e32e80ea7f57e5fef02aea68de585ddb4e3dd14a Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Tue, 5 Aug 2025 10:17:21 -0700 Subject: [PATCH 6/8] chore: Add @fourcube in changeset --- .changeset/good-weeks-tickle.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.changeset/good-weeks-tickle.md b/.changeset/good-weeks-tickle.md index 723e5932b..9210c54e0 100644 --- a/.changeset/good-weeks-tickle.md +++ b/.changeset/good-weeks-tickle.md @@ -3,3 +3,6 @@ --- fix: sanitize icon labels and icon SVGs + +Resolves issue reported by @fourcube + From 20a18971ea6425aa7f083d0f62ea652f7ec8d1ed Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Thu, 7 Aug 2025 13:39:01 +0530 Subject: [PATCH 7/8] chore: Add CVE ID --- .changeset/good-weeks-tickle.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/good-weeks-tickle.md b/.changeset/good-weeks-tickle.md index 9210c54e0..97c0c3660 100644 --- a/.changeset/good-weeks-tickle.md +++ b/.changeset/good-weeks-tickle.md @@ -4,5 +4,4 @@ fix: sanitize icon labels and icon SVGs -Resolves issue reported by @fourcube - +Resolves CVE-2025-54880 reported by @fourcube From aeaf626bb575d923c482c58fc4a827934570e8e4 Mon Sep 17 00:00:00 2001 From: Sidharth Vinod Date: Fri, 8 Aug 2025 18:59:47 +0530 Subject: [PATCH 8/8] fix: Sanitize check in unit test --- packages/mermaid/src/rendering-util/createText.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/mermaid/src/rendering-util/createText.spec.ts b/packages/mermaid/src/rendering-util/createText.spec.ts index e2e13ef7d..dd7bc00b6 100644 --- a/packages/mermaid/src/rendering-util/createText.spec.ts +++ b/packages/mermaid/src/rendering-util/createText.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { replaceIconSubstring } from './createText.js'; +import { sanitizeText } from '../diagram-api/diagramAPI.js'; import mermaid from '../mermaid.js'; +import { replaceIconSubstring } from './createText.js'; describe('replaceIconSubstring', () => { it('converts FontAwesome icon notations to HTML tags', async () => { @@ -56,7 +57,7 @@ describe('replaceIconSubstring', () => { ]); const input = 'Icons galore: fa:fa-bell'; const output = await replaceIconSubstring(input); - const expected = staticBellIconPack.icons.bell.body; + const expected = sanitizeText(staticBellIconPack.icons.bell.body); expect(output).toContain(expected); }); });