VYPR
Medium severityOSV Advisory· Published Aug 19, 2025· Updated Apr 15, 2026

CVE-2025-54881

CVE-2025-54881

Description

Mermaid is a JavaScript based diagramming and charting tool that uses Markdown-inspired text definitions and a renderer to create and modify complex diagrams. In the default configuration of mermaid 10.9.0-rc.1 to 11.9.0, user supplied input for sequence diagram labels is passed to innerHTML during calculation of element size, causing XSS.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
mermaidnpm
>= 11.0.0-alpha.1, < 11.10.011.10.0
mermaidnpm
>= 10.9.0-rc.1, < 10.9.410.9.4

Affected products

1

Patches

2
685516a85ec1

Merge commit from fork

https://github.com/mermaid-js/mermaidSidharth VinodAug 18, 2025via ghsa
9 files changed · +109 57
  • .changeset/tidy-weeks-play.md+7 0 added
    @@ -0,0 +1,7 @@
    +---
    +'mermaid': patch
    +---
    +
    +fix: sanitize KATEX blocks
    +
    +Resolves CVE-2025-54881 reported by @fourcube
    
  • cypress/helpers/util.ts+3 5 modified
    @@ -14,15 +14,15 @@ interface CodeObject {
       mermaid: CypressMermaidConfig;
     }
     
    -const utf8ToB64 = (str: string): string => {
    +export const utf8ToB64 = (str: string): string => {
       return Buffer.from(decodeURIComponent(encodeURIComponent(str))).toString('base64');
     };
     
     const batchId: string =
       'mermaid-batch-' +
       (Cypress.env('useAppli')
         ? Date.now().toString()
    -    : Cypress.env('CYPRESS_COMMIT') || Date.now().toString());
    +    : (Cypress.env('CYPRESS_COMMIT') ?? Date.now().toString()));
     
     export const mermaidUrl = (
       graphStr: string | string[],
    @@ -61,9 +61,7 @@ export const imgSnapshotTest = (
         sequence: {
           ...(_options.sequence ?? {}),
           actorFontFamily: 'courier',
    -      noteFontFamily: _options.sequence?.noteFontFamily
    -        ? _options.sequence.noteFontFamily
    -        : 'courier',
    +      noteFontFamily: _options.sequence?.noteFontFamily ?? 'courier',
           messageFontFamily: 'courier',
         },
       };
    
  • cypress/integration/other/xss.spec.js+23 1 modified
    @@ -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,26 @@ describe('XSS', () => {
         cy.wait(1000);
         cy.get('#the-malware').should('not.exist');
       });
    +
    +  it('should sanitize katex blocks', () => {
    +    const str = JSON.stringify({
    +      code: `sequenceDiagram
    +    participant A as Alice<img src="x" onerror="xssAttack()">$$\\text{Alice}$$
    +    A->>John: Hello John, how are you?`,
    +    });
    +    imgSnapshotTest(utf8ToB64(str), {}, true);
    +    cy.wait(1000);
    +    cy.get('#the-malware').should('not.exist');
    +  });
    +
    +  it('should sanitize labels', () => {
    +    const str = JSON.stringify({
    +      code: `erDiagram
    +    "<img src=x onerror=xssAttack()>" ||--|| ENTITY2 : "<img src=x onerror=xssAttack()>"
    +    `,
    +    });
    +    imgSnapshotTest(utf8ToB64(str), {}, true);
    +    cy.wait(1000);
    +    cy.get('#the-malware').should('not.exist');
    +  });
     });
    
  • cypress/platform/viewer.js+2 2 modified
    @@ -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);
         }
       }
     };
    
  • packages/mermaid/src/dagre-wrapper/createLabel.js+8 7 modified
    @@ -1,9 +1,9 @@
     import { select } from 'd3';
    -import { log } from '../logger.js';
     import { getConfig } from '../diagram-api/diagramAPI.js';
    -import { evaluate } from '../diagrams/common/common.js';
    -import { decodeEntities } from '../utils.js';
    +import { evaluate, sanitizeText } from '../diagrams/common/common.js';
    +import { log } from '../logger.js';
     import { replaceIconSubstring } from '../rendering-util/createText.js';
    +import { decodeEntities } from '../utils.js';
     
     /**
      * @param dom
    @@ -19,14 +19,14 @@ function applyStyle(dom, styleFn) {
      * @param {any} node
      * @returns {SVGForeignObjectElement} Node
      */
    -function addHtmlLabel(node) {
    +function addHtmlLabel(node, config) {
       const fo = select(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'));
       const div = fo.append('xhtml:div');
     
       const label = node.label;
       const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
       const span = div.append('span');
    -  span.html(label);
    +  span.html(sanitizeText(label, config));
       applyStyle(span, node.labelStyle);
       span.attr('class', labelClass);
     
    @@ -49,7 +49,8 @@ const createLabel = async (_vertexText, style, isTitle, isNode) => {
       if (typeof vertexText === 'object') {
         vertexText = vertexText[0];
       }
    -  if (evaluate(getConfig().flowchart.htmlLabels)) {
    +  const config = getConfig();
    +  if (evaluate(config.flowchart.htmlLabels)) {
         // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
         vertexText = vertexText.replace(/\\n|\n/g, '<br />');
         log.debug('vertexText' + vertexText);
    @@ -59,7 +60,7 @@ const createLabel = async (_vertexText, style, isTitle, isNode) => {
           label,
           labelStyle: style.replace('fill:', 'color:'),
         };
    -    let vertexNode = addHtmlLabel(node);
    +    let vertexNode = addHtmlLabel(node, config);
         // vertexNode.parentNode.removeChild(vertexNode);
         return vertexNode;
       } else {
    
  • packages/mermaid/src/diagrams/common/common.ts+16 10 modified
    @@ -311,9 +311,8 @@ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.leng
      * @returns Object containing \{width, height\}
      */
     export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
    -  text = await renderKatex(text, config);
       const divElem = document.createElement('div');
    -  divElem.innerHTML = text;
    +  divElem.innerHTML = await renderKatexSanitized(text, config);
       divElem.id = 'katex-temp';
       divElem.style.visibility = 'hidden';
       divElem.style.position = 'absolute';
    @@ -325,14 +324,7 @@ export const calculateMathMLDimensions = async (text: string, config: MermaidCon
       return dim;
     };
     
    -/**
    - * Attempts to render and return the KaTeX portion of a string with MathML
    - *
    - * @param text - The text to test
    - * @param config - Configuration for Mermaid
    - * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
    - */
    -export const renderKatex = async (text: string, config: MermaidConfig): Promise<string> => {
    +const renderKatexUnsanitized = async (text: string, config: MermaidConfig): Promise<string> => {
       if (!hasKatex(text)) {
         return text;
       }
    @@ -373,6 +365,20 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
       );
     };
     
    +/**
    + * Attempts to render and return the KaTeX portion of a string with MathML
    + *
    + * @param text - The text to test
    + * @param config - Configuration for Mermaid
    + * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
    + */
    +export const renderKatexSanitized = async (
    +  text: string,
    +  config: MermaidConfig
    +): Promise<string> => {
    +  return sanitizeText(await renderKatexUnsanitized(text, config), config);
    +};
    +
     export default {
       getRows,
       sanitizeText,
    
  • packages/mermaid/src/diagrams/sequence/svgDraw.js+10 6 modified
    @@ -1,8 +1,12 @@
    -import common, { calculateMathMLDimensions, hasKatex, renderKatex } from '../common/common.js';
    -import * as svgDrawCommon from '../common/svgDrawCommon.js';
    -import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
     import { sanitizeUrl } from '@braintree/sanitize-url';
     import * as configApi from '../../config.js';
    +import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
    +import common, {
    +  calculateMathMLDimensions,
    +  hasKatex,
    +  renderKatexSanitized,
    +} from '../common/common.js';
    +import * as svgDrawCommon from '../common/svgDrawCommon.js';
     
     export const ACTOR_TYPE_WIDTH = 18 * 2;
     const TOP_ACTOR_CLASS = 'actor-top';
    @@ -87,13 +91,13 @@ const popupMenuToggle = function (popId) {
     
     export const drawKatex = async function (elem, textData, msgModel = null) {
       let textElem = elem.append('foreignObject');
    -  const lines = await renderKatex(textData.text, configApi.getConfig());
    +  const linesSanitized = await renderKatexSanitized(textData.text, configApi.getConfig());
     
       const divElem = textElem
         .append('xhtml:div')
         .attr('style', 'width: fit-content;')
         .attr('xmlns', 'http://www.w3.org/1999/xhtml')
    -    .html(lines);
    +    .html(linesSanitized);
       const dim = divElem.node().getBoundingClientRect();
     
       textElem.attr('height', Math.round(dim.height)).attr('width', Math.round(dim.width));
    @@ -965,7 +969,7 @@ const _drawTextCandidateFunc = (function () {
           .append('div')
           .style('text-align', 'center')
           .style('vertical-align', 'middle')
    -      .html(await renderKatex(content, configApi.getConfig()));
    +      .html(await renderKatexSanitized(content, configApi.getConfig()));
     
         byTspan(content, s, x, y, width, height, textAttrs, conf);
         _setTextAttrs(text, textAttrs);
    
  • packages/mermaid/src/rendering-util/createText.ts+23 15 modified
    @@ -2,9 +2,8 @@
     // @ts-nocheck TODO: Fix types
     import { select } from 'd3';
     import type { MermaidConfig } from '../config.type.js';
    -import { getConfig, sanitizeText } from '../diagram-api/diagramAPI.js';
     import type { SVGGroup } from '../diagram-api/types.js';
    -import common, { hasKatex, renderKatex } from '../diagrams/common/common.js';
    +import common, { hasKatex, renderKatexSanitized, sanitizeText } from '../diagrams/common/common.js';
     import type { D3TSpanElement, D3TextElement } from '../diagrams/common/commonTypes.js';
     import { log } from '../logger.js';
     import { markdownToHTML, markdownToLines } from '../rendering-util/handle-markdown-text.js';
    @@ -19,21 +18,28 @@ function applyStyle(dom, styleFn) {
       }
     }
     
    -async function addHtmlSpan(element, node, width, classes, addBackground = false) {
    +async function addHtmlSpan(
    +  element,
    +  node,
    +  width,
    +  classes,
    +  addBackground = false,
    +  // TODO: Make config mandatory
    +  config: MermaidConfig = {}
    +) {
       const fo = element.append('foreignObject');
       // This is not the final width but used in order to make sure the foreign
       // object in firefox gets a width at all. The final width is fetched from the div
       fo.attr('width', `${10 * width}px`);
       fo.attr('height', `${10 * width}px`);
     
       const div = fo.append('xhtml:div');
    -  let label = node.label;
    -  if (node.label && hasKatex(node.label)) {
    -    label = await renderKatex(node.label.replace(common.lineBreakRegex, '\n'), getConfig());
    -  }
    +  const sanitizedLabel = hasKatex(node.label)
    +    ? await renderKatexSanitized(node.label.replace(common.lineBreakRegex, '\n'), config)
    +    : sanitizeText(node.label, config);
       const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
       const span = div.append('span');
    -  span.html(label);
    +  span.html(sanitizedLabel);
       applyStyle(span, node.labelStyle);
       span.attr('class', `${labelClass} ${classes}`);
     
    @@ -56,9 +62,6 @@ async function addHtmlSpan(element, node, width, classes, addBackground = false)
         bbox = div.node().getBoundingClientRect();
       }
     
    -  // fo.style('width', bbox.width);
    -  // fo.style('height', bbox.height);
    -
       return fo.node();
     }
     
    @@ -181,9 +184,14 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
     /**
      * Convert fontawesome labels into fontawesome icons by using a regex pattern
      * @param text - The raw string to convert
    + * @param config - Mermaid config
      * @returns string with fontawesome icons as svg if the icon is registered otherwise as i tags
      */
    -export async function replaceIconSubstring(text: string) {
    +export async function replaceIconSubstring(
    +  text: string,
    +  // TODO: Make config mandatory
    +  config: MermaidConfig = {}
    +): Promise<string> {
       const pendingReplacements: Promise<string>[] = [];
       // cspell: disable-next-line
       text.replace(/(fa[bklrs]?):fa-([\w-]+)/g, (fullMatch, prefix, iconName) => {
    @@ -193,7 +201,7 @@ export async function replaceIconSubstring(text: string) {
             if (await isIconAvailable(registeredIconName)) {
               return await getIconSVG(registeredIconName, undefined, { class: 'label-icon' });
             } else {
    -          return `<i class='${sanitizeText(fullMatch).replace(':', ' ')}'></i>`;
    +          return `<i class='${sanitizeText(fullMatch, config).replace(':', ' ')}'></i>`;
             }
           })()
         );
    @@ -236,7 +244,7 @@ export const createText = async (
         // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
     
         const htmlText = markdownToHTML(text, config);
    -    const decodedReplacedText = await replaceIconSubstring(decodeEntities(htmlText));
    +    const decodedReplacedText = await replaceIconSubstring(decodeEntities(htmlText), config);
     
         //for Katex the text could contain escaped characters, \\relax that should be transformed to \relax
         const inputForKatex = text.replace(/\\\\/g, '\\');
    @@ -246,7 +254,7 @@ export const createText = async (
           label: hasKatex(text) ? inputForKatex : decodedReplacedText,
           labelStyle: style.replace('fill:', 'color:'),
         };
    -    const vertexNode = await addHtmlSpan(el, node, width, classes, addSvgBackground);
    +    const vertexNode = await addHtmlSpan(el, node, width, classes, addSvgBackground, config);
         return vertexNode;
       } else {
         //sometimes the user might add br tags with 1 or more spaces in between, so we need to replace them with <br/>
    
  • packages/mermaid/src/rendering-util/rendering-elements/createLabel.js+17 11 modified
    @@ -1,7 +1,12 @@
     import { select } from 'd3';
    -import { log } from '../../logger.js';
     import { getConfig } from '../../diagram-api/diagramAPI.js';
    -import common, { evaluate, renderKatex, hasKatex } from '../../diagrams/common/common.js';
    +import common, {
    +  evaluate,
    +  hasKatex,
    +  renderKatexSanitized,
    +  sanitizeText,
    +} from '../../diagrams/common/common.js';
    +import { log } from '../../logger.js';
     import { decodeEntities } from '../../utils.js';
     
     /**
    @@ -22,20 +27,21 @@ async function addHtmlLabel(node) {
       const fo = select(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject'));
       const div = fo.append('xhtml:div');
     
    +  const config = getConfig();
       let label = node.label;
       if (node.label && hasKatex(node.label)) {
    -    label = await renderKatex(node.label.replace(common.lineBreakRegex, '\n'), getConfig());
    +    label = await renderKatexSanitized(node.label.replace(common.lineBreakRegex, '\n'), config);
       }
       const labelClass = node.isNode ? 'nodeLabel' : 'edgeLabel';
    -  div.html(
    +  const labelSpan =
         '<span class="' +
    -      labelClass +
    -      '" ' +
    -      (node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + // codeql [js/html-constructed-from-input] : false positive
    -      '>' +
    -      label +
    -      '</span>'
    -  );
    +    labelClass +
    +    '" ' +
    +    (node.labelStyle ? 'style="' + node.labelStyle + '"' : '') + // codeql [js/html-constructed-from-input] : false positive
    +    '>' +
    +    label +
    +    '</span>';
    +  div.html(sanitizeText(labelSpan, config));
     
       applyStyle(div, node.labelStyle);
       div.style('display', 'inline-block');
    
5c69e5fdb004

feat(katex): optimized importing of katex

https://github.com/mermaid-js/mermaidNicolasNewmanJun 23, 2023via ghsa
5 files changed · +93 98
  • packages/mermaid/src/diagrams/common/common.ts+6 13 modified
    @@ -1,6 +1,4 @@
     import DOMPurify from 'dompurify';
    -// @ts-ignore @types/katex does not work
    -import katex from 'katex';
     import { MermaidConfig } from '../../config.type.js';
     
     export const lineBreakRegex = /<br\s*\/?>/gi;
    @@ -219,8 +217,8 @@ export const hasKatex = (text: string): boolean => (text.match(katexRegex)?.leng
      * @param config - Configuration for Mermaid
      * @returns Object containing \{width, height\}
      */
    -export const calculateMathMLDimensions = (text: string, config: MermaidConfig) => {
    -  text = renderKatex(text, config);
    +export const calculateMathMLDimensions = async (text: string, config: MermaidConfig) => {
    +  text = await renderKatex(text, config);
       const divElem = document.createElement('div');
       divElem.innerHTML = text;
       divElem.id = 'katex-temp';
    @@ -234,22 +232,17 @@ export const calculateMathMLDimensions = (text: string, config: MermaidConfig) =
       return dim;
     };
     
    -// export const temp = (text: string, config: MermaidConfig) => {
    -//   return renderKatex(text, config).split(lineBreakRegex).map((text) =>
    -//     hasKatex(text) ?
    -//        `<div style="display: flex;">${text}</div>` :
    -//        `<div>${text}</div>`).join('');
    -// }
    -
     /**
      * Attempts to render and return the KaTeX portion of a string with MathML
      *
      * @param text - The text to test
      * @param config - Configuration for Mermaid
      * @returns String containing MathML if KaTeX is supported, or an error message if it is not and stylesheets aren't present
      */
    -export const renderKatex = (text: string, config: MermaidConfig): string => {
    -  if (isMathMLSupported() || (!isMathMLSupported() && config.legacyMathML)) {
    +export const renderKatex = async (text: string, config: MermaidConfig): Promise<string> => {
    +  if ((hasKatex(text) && isMathMLSupported()) || (!isMathMLSupported() && config.legacyMathML)) {
    +    // @ts-ignore @types/katex does not work
    +    const katex = (await import('katex')).default;
         return text
           .split(lineBreakRegex)
           .map((line) =>
    
  • packages/mermaid/src/diagrams/flowchart/flowRenderer.js+11 11 modified
    @@ -28,13 +28,13 @@ export const setConf = function (cnf) {
      * @param _doc
      * @param diagObj
      */
    -export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
    +export const addVertices = async function (vert, g, svgId, root, _doc, diagObj) {
       const svg = !root ? select(`[id="${svgId}"]`) : root.select(`[id="${svgId}"]`);
       const doc = !_doc ? document : _doc;
       const keys = Object.keys(vert);
     
       // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
    -  keys.forEach(function (id) {
    +  for (const id of keys) {
         const vertex = vert[id];
     
         /**
    @@ -57,7 +57,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
         if (evaluate(getConfig().flowchart.htmlLabels)) {
           // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
           const node = {
    -        label: renderKatex(
    +        label: await renderKatex(
               vertexText.replace(
                 /fa[blrs]?:fa-[\w-]+/g,
                 (s) => `<i class='${s.replace(':', ' ')}'></i>`
    @@ -153,7 +153,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
           style: styles.style,
           id: diagObj.db.lookUpDomId(vertex.id),
         });
    -  });
    +  }
     };
     
     /**
    @@ -163,7 +163,7 @@ export const addVertices = function (vert, g, svgId, root, _doc, diagObj) {
      * @param {object} g The graph object
      * @param diagObj
      */
    -export const addEdges = function (edges, g, diagObj) {
    +export const addEdges = async function (edges, g, diagObj) {
       let cnt = 0;
     
       let defaultStyle;
    @@ -175,7 +175,7 @@ export const addEdges = function (edges, g, diagObj) {
         defaultLabelStyle = defaultStyles.labelStyle;
       }
     
    -  edges.forEach(function (edge) {
    +  for (const edge of edges) {
         cnt++;
     
         // Identify Link
    @@ -242,7 +242,7 @@ export const addEdges = function (edges, g, diagObj) {
             edgeData.labelType = 'html';
             edgeData.label = `<span id="L-${linkId}" class="edgeLabel L-${linkNameStart}' L-${linkNameEnd}" style="${
               edgeData.labelStyle
    -        }">${renderKatex(
    +        }">${await renderKatex(
               edge.text.replace(
                 /fa[blrs]?:fa-[\w-]+/g,
                 (s) => `<i class='${s.replace(':', ' ')}'></i>`
    @@ -267,7 +267,7 @@ export const addEdges = function (edges, g, diagObj) {
     
         // Add the edge to the graph
         g.setEdge(diagObj.db.lookUpDomId(edge.start), diagObj.db.lookUpDomId(edge.end), edgeData, cnt);
    -  });
    +  }
     };
     
     /**
    @@ -298,7 +298,7 @@ export const getClasses = function (text, diagObj) {
      * @param _version
      * @param diagObj
      */
    -export const draw = function (text, id, _version, diagObj) {
    +export const draw = async function (text, id, _version, diagObj) {
       log.info('Drawing flowchart');
       diagObj.db.clear();
       const { securityLevel, flowchart: conf } = getConfig();
    @@ -372,8 +372,8 @@ export const draw = function (text, id, _version, diagObj) {
           g.setParent(diagObj.db.lookUpDomId(subG.nodes[j]), diagObj.db.lookUpDomId(subG.id));
         }
       }
    -  addVertices(vert, g, id, root, doc, diagObj);
    -  addEdges(edges, g, diagObj);
    +  await addVertices(vert, g, id, root, doc, diagObj);
    +  await addEdges(edges, g, diagObj);
     
       // Create the renderer
       const render = new Render();
    
  • packages/mermaid/src/diagrams/flowchart/flowRenderer-v2.js+10 10 modified
    @@ -30,12 +30,12 @@ export const setConf = function (cnf) {
      * @param doc
      * @param diagObj
      */
    -export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
    +export const addVertices = async function (vert, g, svgId, root, doc, diagObj) {
       const svg = root.select(`[id="${svgId}"]`);
       const keys = Object.keys(vert);
     
       // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
    -  keys.forEach(function (id) {
    +  for (const id of keys) {
         const vertex = vert[id];
     
         /**
    @@ -143,7 +143,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
           default:
             _shape = 'rect';
         }
    -    const labelText = renderKatex(vertexText, getConfig());
    +    const labelText = await renderKatex(vertexText, getConfig());
     
         // Add the node
         g.setNode(vertex.id, {
    @@ -185,7 +185,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
           props: vertex.props,
           padding: getConfig().flowchart.padding,
         });
    -  });
    +  }
     };
     
     /**
    @@ -195,7 +195,7 @@ export const addVertices = function (vert, g, svgId, root, doc, diagObj) {
      * @param {object} g The graph object
      * @param diagObj
      */
    -export const addEdges = function (edges, g, diagObj) {
    +export const addEdges = async function (edges, g, diagObj) {
       log.info('abc78 edges = ', edges);
       let cnt = 0;
       let linkIdCnt = {};
    @@ -209,7 +209,7 @@ export const addEdges = function (edges, g, diagObj) {
         defaultLabelStyle = defaultStyles.labelStyle;
       }
     
    -  edges.forEach(function (edge) {
    +  for (const edge of edges) {
         cnt++;
     
         // Identify Link
    @@ -318,7 +318,7 @@ export const addEdges = function (edges, g, diagObj) {
           edgeData.labelpos = 'c';
         }
         edgeData.labelType = edge.labelType;
    -    edgeData.label = renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig());
    +    edgeData.label = await renderKatex(edge.text.replace(common.lineBreakRegex, '\n'), getConfig());
     
         if (edge.style === undefined) {
           edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';
    @@ -331,7 +331,7 @@ export const addEdges = function (edges, g, diagObj) {
     
         // Add the edge to the graph
         g.setEdge(edge.start, edge.end, edgeData, cnt);
    -  });
    +  }
     };
     
     /**
    @@ -438,8 +438,8 @@ export const draw = async function (text, id, _version, diagObj) {
           g.setParent(subG.nodes[j], subG.id);
         }
       }
    -  addVertices(vert, g, id, root, doc, diagObj);
    -  addEdges(edges, g, diagObj);
    +  await addVertices(vert, g, id, root, doc, diagObj);
    +  await addEdges(edges, g, diagObj);
     
       // Add custom shapes
       // flowChartShapes.addToRenderV2(addShape);
    
  • packages/mermaid/src/diagrams/sequence/sequenceRenderer.ts+46 44 modified
    @@ -237,7 +237,7 @@ interface NoteModel {
      * @param elem - The diagram to draw to.
      * @param noteModel - Note model options.
      */
    -const drawNote = function (elem: any, noteModel: NoteModel) {
    +const drawNote = async function (elem: any, noteModel: NoteModel) {
       bounds.bumpVerticalPos(conf.boxMargin);
       noteModel.height = conf.boxMargin;
       noteModel.starty = bounds.getVerticalPos();
    @@ -263,7 +263,7 @@ const drawNote = function (elem: any, noteModel: NoteModel) {
       textObj.textMargin = conf.noteMargin;
       textObj.valign = 'center';
     
    -  const textElem = hasKatex(textObj.text) ? drawKatex(g, textObj) : drawText(g, textObj);
    +  const textElem = hasKatex(textObj.text) ? await drawKatex(g, textObj) : drawText(g, textObj);
     
       const textHeight = Math.round(
         textElem
    @@ -311,13 +311,13 @@ const actorFont = (cnf) => {
      * @param msgModel - The model containing fields describing a message
      * @returns `lineStartY` - The Y coordinate at which the message line starts
      */
    -function boundMessage(_diagram, msgModel): number {
    +async function boundMessage(_diagram, msgModel): number {
       bounds.bumpVerticalPos(10);
       const { startx, stopx, message } = msgModel;
       const lines = common.splitBreaks(message).length;
       const isKatexMsg = hasKatex(message);
       const textDims = isKatexMsg
    -    ? calculateMathMLDimensions(message, configApi.getConfig())
    +    ? await calculateMathMLDimensions(message, configApi.getConfig())
         : utils.calculateTextDimensions(message, messageFont(conf));
     
       if (!isKatexMsg) {
    @@ -365,7 +365,7 @@ function boundMessage(_diagram, msgModel): number {
      * @param lineStartY - The Y coordinate at which the message line starts
      * @param diagObj - The diagram object.
      */
    -const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
    +const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
       const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
       const textDims = utils.calculateTextDimensions(message, messageFont(conf));
       const textObj = svgDrawCommon.getTextObj();
    @@ -384,7 +384,7 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
       textObj.tspan = false;
     
       hasKatex(textObj.text)
    -    ? drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY })
    +    ? await drawKatex(diagram, textObj, { startx, stopx, starty: lineStartY })
         : drawText(diagram, textObj);
     
       const textWidth = textDims.width;
    @@ -485,7 +485,7 @@ const drawMessage = function (diagram, msgModel, lineStartY: number, diagObj: Di
       }
     };
     
    -export const drawActors = function (
    +export const drawActors = async function (
       diagram,
       actors,
       actorKeys,
    @@ -539,7 +539,7 @@ export const drawActors = function (
         actor.y = bounds.getVerticalPos();
     
         // Draw the box with the attached line
    -    const height = svgDraw.drawActor(diagram, actor, conf, isFooter);
    +    const height = await svgDraw.drawActor(diagram, actor, conf, isFooter);
         maxHeight = common.getMax(maxHeight, height);
         bounds.insert(actor.x, verticalPos, actor.x + actor.width, actor.height);
     
    @@ -648,7 +648,7 @@ function adjustLoopHeightForWrap(loopWidths, msg, preMargin, postMargin, addLoop
      * @param _version - Mermaid version from package.json
      * @param diagObj - A standard diagram containing the db and the text and type etc of the diagram
      */
    -export const draw = function (_text: string, id: string, _version: string, diagObj: Diagram) {
    +export const draw = async function (_text: string, id: string, _version: string, diagObj: Diagram) {
       const { securityLevel, sequence } = configApi.getConfig();
       conf = sequence;
       diagObj.db.clear();
    @@ -679,8 +679,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
       const title = diagObj.db.getDiagramTitle();
       const hasBoxes = diagObj.db.hasAtLeastOneBox();
       const hasBoxTitles = diagObj.db.hasAtLeastOneBoxWithTitle();
    -  const maxMessageWidthPerActor = getMaxMessageWidthPerActor(actors, messages, diagObj);
    -  conf.height = calculateActorMargins(actors, maxMessageWidthPerActor, boxes);
    +  const maxMessageWidthPerActor = await getMaxMessageWidthPerActor(actors, messages, diagObj);
    +  conf.height = await calculateActorMargins(actors, maxMessageWidthPerActor, boxes);
     
       svgDraw.insertComputerIcon(diagram);
       svgDraw.insertDatabaseIcon(diagram);
    @@ -693,8 +693,8 @@ export const draw = function (_text: string, id: string, _version: string, diagO
         }
       }
     
    -  drawActors(diagram, actors, actorKeys, 0, conf, messages, false);
    -  const loopWidths = calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
    +  await drawActors(diagram, actors, actorKeys, 0, conf, messages, false);
    +  const loopWidths = await calculateLoopBounds(messages, actors, maxMessageWidthPerActor, diagObj);
     
       // The arrow head definition is attached to the svg once
       svgDraw.insertArrowHead(diagram);
    @@ -727,14 +727,14 @@ export const draw = function (_text: string, id: string, _version: string, diagO
       let sequenceIndex = 1;
       let sequenceIndexStep = 1;
       const messagesToDraw = [];
    -  messages.forEach(function (msg) {
    +  for (const msg of messages) {
         let loopModel, noteModel, msgModel;
     
         switch (msg.type) {
           case diagObj.db.LINETYPE.NOTE:
             bounds.resetVerticalPos();
             noteModel = msg.noteModel;
    -        drawNote(diagram, noteModel);
    +        await drawNote(diagram, noteModel);
             break;
           case diagObj.db.LINETYPE.ACTIVE_START:
             bounds.newActivation(msg, diagram, actors);
    @@ -753,7 +753,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.LOOP_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'loop', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -779,7 +779,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.OPT_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'opt', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -803,7 +803,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.ALT_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'alt', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -829,7 +829,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.PAR_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'par', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'par', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -862,7 +862,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.CRITICAL_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'critical', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -877,7 +877,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
             break;
           case diagObj.db.LINETYPE.BREAK_END:
             loopModel = bounds.endLoop();
    -        svgDraw.drawLoop(diagram, loopModel, 'break', conf);
    +        await svgDraw.drawLoop(diagram, loopModel, 'break', conf);
             bounds.bumpVerticalPos(loopModel.stopy - bounds.getVerticalPos());
             bounds.models.addLoop(loopModel);
             break;
    @@ -889,7 +889,7 @@ export const draw = function (_text: string, id: string, _version: string, diagO
               msgModel.starty = bounds.getVerticalPos();
               msgModel.sequenceIndex = sequenceIndex;
               msgModel.sequenceVisible = diagObj.db.showSequenceNumbers();
    -          const lineStartY = boundMessage(diagram, msgModel);
    +          const lineStartY = await boundMessage(diagram, msgModel);
               messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
               bounds.models.addMessage(msgModel);
             } catch (e) {
    @@ -912,28 +912,30 @@ export const draw = function (_text: string, id: string, _version: string, diagO
         ) {
           sequenceIndex = sequenceIndex + sequenceIndexStep;
         }
    -  });
    +  }
     
    -  messagesToDraw.forEach((e) => drawMessage(diagram, e.messageModel, e.lineStartY, diagObj));
    +  for (const e of messagesToDraw) {
    +    await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj);
    +  }
     
       if (conf.mirrorActors) {
         // Draw actors below diagram
         bounds.bumpVerticalPos(conf.boxMargin * 2);
    -    drawActors(diagram, actors, actorKeys, bounds.getVerticalPos(), conf, messages, true);
    +    await drawActors(diagram, actors, actorKeys, bounds.getVerticalPos(), conf, messages, true);
         bounds.bumpVerticalPos(conf.boxMargin);
         fixLifeLineHeights(diagram, bounds.getVerticalPos());
       }
     
    -  bounds.models.boxes.forEach(function (box) {
    +  for (const box of bounds.models.boxes) {
         box.height = bounds.getVerticalPos() - box.y;
         bounds.insert(box.x, box.y, box.x + box.width, box.height);
         box.startx = box.x;
         box.starty = box.y;
         box.stopx = box.startx + box.width;
         box.stopy = box.starty + box.height;
         box.stroke = 'rgb(0,0,0, 0.5)';
    -    svgDraw.drawBox(diagram, box, conf);
    -  });
    +    await svgDraw.drawBox(diagram, box, conf);
    +  }
     
       if (hasBoxes) {
         bounds.bumpVerticalPos(conf.boxMargin);
    @@ -1004,14 +1006,14 @@ export const draw = function (_text: string, id: string, _version: string, diagO
      * @param diagObj - The diagram object.
      * @returns The max message width of each actor.
      */
    -function getMaxMessageWidthPerActor(
    +async function getMaxMessageWidthPerActor(
       actors: { [id: string]: any },
       messages: any[],
       diagObj: Diagram
    -): { [id: string]: number } {
    +): Promise<{ [id: string]: number }> {
       const maxMessageWidthPerActor = {};
     
    -  messages.forEach(function (msg) {
    +  for (const msg of messages) {
         if (actors[msg.to] && actors[msg.from]) {
           const actor = actors[msg.to];
     
    @@ -1033,7 +1035,7 @@ function getMaxMessageWidthPerActor(
             ? utils.wrapLabel(msg.message, conf.width - 2 * conf.wrapPadding, textFont)
             : msg.message;
           const messageDimensions = hasKatex(wrappedMessage)
    -        ? calculateMathMLDimensions(msg.message, configApi.getConfig())
    +        ? await calculateMathMLDimensions(msg.message, configApi.getConfig())
             : utils.calculateTextDimensions(wrappedMessage, textFont);
           const messageWidth = messageDimensions.width + 2 * conf.wrapPadding;
     
    @@ -1099,7 +1101,7 @@ function getMaxMessageWidthPerActor(
             }
           }
         }
    -  });
    +  }
     
       log.debug('maxMessageWidthPerActor:', maxMessageWidthPerActor);
       return maxMessageWidthPerActor;
    @@ -1130,13 +1132,13 @@ const getRequiredPopupWidth = function (actor) {
      * @param actorToMessageWidth - A map of actor key → max message width it holds
      * @param boxes - The boxes around the actors if any
      */
    -function calculateActorMargins(
    +async function calculateActorMargins(
       actors: { [id: string]: any },
    -  actorToMessageWidth: ReturnType<typeof getMaxMessageWidthPerActor>,
    +  actorToMessageWidth: Awaited<ReturnType<typeof getMaxMessageWidthPerActor>>,
       boxes
     ) {
       let maxHeight = 0;
    -  Object.keys(actors).forEach((prop) => {
    +  for (const prop of Object.keys(actors)) {
         const actor = actors[prop];
         if (actor.wrap) {
           actor.description = utils.wrapLabel(
    @@ -1146,7 +1148,7 @@ function calculateActorMargins(
           );
         }
         const actDims = hasKatex(actor.description)
    -      ? calculateMathMLDimensions(actor.description, configApi.getConfig())
    +      ? await calculateMathMLDimensions(actor.description, configApi.getConfig())
           : utils.calculateTextDimensions(actor.description, actorFont(conf));
     
         actor.width = actor.wrap
    @@ -1155,7 +1157,7 @@ function calculateActorMargins(
     
         actor.height = actor.wrap ? common.getMax(actDims.height, conf.height) : conf.height;
         maxHeight = common.getMax(maxHeight, actor.height);
    -  });
    +  }
     
       for (const actorKey in actorToMessageWidth) {
         const actor = actors[actorKey];
    @@ -1206,13 +1208,13 @@ function calculateActorMargins(
       return common.getMax(maxHeight, conf.height);
     }
     
    -const buildNoteModel = function (msg, actors, diagObj) {
    +const buildNoteModel = async function (msg, actors, diagObj) {
       const startx = actors[msg.from].x;
       const stopx = actors[msg.to].x;
       const shouldWrap = msg.wrap && msg.message;
     
       let textDimensions: { width: number; height: number; lineHeight?: number } = hasKatex(msg.message)
    -    ? calculateMathMLDimensions(msg.message, configApi.getConfig())
    +    ? await calculateMathMLDimensions(msg.message, configApi.getConfig())
         : utils.calculateTextDimensions(
             shouldWrap ? utils.wrapLabel(msg.message, conf.width, noteFont(conf)) : msg.message,
             noteFont(conf)
    @@ -1338,12 +1340,12 @@ const buildMessageModel = function (msg, actors, diagObj) {
       };
     };
     
    -const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagObj) {
    +const calculateLoopBounds = async function (messages, actors, _maxWidthPerActor, diagObj) {
       const loops = {};
       const stack = [];
       let current, noteModel, msgModel;
     
    -  messages.forEach(function (msg) {
    +  for (const msg of messages) {
         msg.id = utils.random({ length: 10 });
         switch (msg.type) {
           case diagObj.db.LINETYPE.LOOP_START:
    @@ -1406,7 +1408,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
         }
         const isNote = msg.placement !== undefined;
         if (isNote) {
    -      noteModel = buildNoteModel(msg, actors, diagObj);
    +      noteModel = await buildNoteModel(msg, actors, diagObj);
           msg.noteModel = noteModel;
           stack.forEach((stk) => {
             current = stk;
    @@ -1445,7 +1447,7 @@ const calculateLoopBounds = function (messages, actors, _maxWidthPerActor, diagO
             });
           }
         }
    -  });
    +  }
       bounds.activations = [];
       log.debug('Loop type widths:', loops);
       return loops;
    
  • packages/mermaid/src/diagrams/sequence/svgDraw.js+20 20 modified
    @@ -119,9 +119,9 @@ const popupMenuDownFunc = function (popupId) {
       }
     };
     
    -export const drawKatex = function (elem, textData, msgModel = null) {
    +export const drawKatex = async function (elem, textData, msgModel = null) {
       let textElem = elem.append('foreignObject');
    -  const lines = renderKatex(textData.text, configApi.getConfig());
    +  const lines = await renderKatex(textData.text, configApi.getConfig());
     
       const divElem = textElem
         .append('xhtml:div')
    @@ -353,7 +353,7 @@ export const fixLifeLineHeights = (diagram, bounds) => {
      * @param {any} conf - DrawText implementation discriminator object
      * @param {boolean} isFooter - If the actor is the footer one
      */
    -const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
    +const drawActorTypeParticipant = async function (elem, actor, conf, isFooter) {
       const center = actor.x + actor.width / 2;
       const centerY = actor.y + 5;
     
    @@ -407,7 +407,7 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
         }
       }
     
    -  _drawTextCandidateFunc(conf, hasKatex(actor.description))(
    +  await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
         actor.description,
         g,
         rect.x,
    @@ -428,10 +428,9 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
       return height;
     };
     
    -const drawActorTypeActor = function (elem, actor, conf, isFooter) {
    +const drawActorTypeActor = async function (elem, actor, conf, isFooter) {
       const center = actor.x + actor.width / 2;
       const centerY = actor.y + 80;
    -
       if (!isFooter) {
         actorCnt++;
         elem
    @@ -496,7 +495,7 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
       const bounds = actElem.node().getBBox();
       actor.height = bounds.height;
     
    -  _drawTextCandidateFunc(conf, hasKatex(actor.description))(
    +  await _drawTextCandidateFunc(conf, hasKatex(actor.description))(
         actor.description,
         actElem,
         rect.x,
    @@ -510,21 +509,21 @@ const drawActorTypeActor = function (elem, actor, conf, isFooter) {
       return actor.height;
     };
     
    -export const drawActor = function (elem, actor, conf, isFooter) {
    +export const drawActor = async function (elem, actor, conf, isFooter) {
       switch (actor.type) {
         case 'actor':
    -      return drawActorTypeActor(elem, actor, conf, isFooter);
    +      return await drawActorTypeActor(elem, actor, conf, isFooter);
         case 'participant':
    -      return drawActorTypeParticipant(elem, actor, conf, isFooter);
    +      return await drawActorTypeParticipant(elem, actor, conf, isFooter);
       }
     };
     
    -export const drawBox = function (elem, box, conf) {
    +export const drawBox = async function (elem, box, conf) {
       const boxplustextGroup = elem.append('g');
       const g = boxplustextGroup;
       drawBackgroundRect(g, box);
       if (box.name) {
    -    _drawTextCandidateFunc(conf)(
    +    await _drawTextCandidateFunc(conf)(
           box.name,
           g,
           box.x,
    @@ -571,7 +570,7 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc
      * @param {any} conf - Diagram configuration
      * @returns {any}
      */
    -export const drawLoop = function (elem, loopModel, labelText, conf) {
    +export const drawLoop = async function (elem, loopModel, labelText, conf) {
       const {
         boxMargin,
         boxTextMargin,
    @@ -633,10 +632,10 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
       txt.fontWeight = fontWeight;
       txt.wrap = true;
     
    -  let textElem = hasKatex(txt.text) ? drawKatex(g, txt, loopModel) : drawText(g, txt);
    +  let textElem = hasKatex(txt.text) ? await drawKatex(g, txt, loopModel) : drawText(g, txt);
     
       if (loopModel.sectionTitles !== undefined) {
    -    loopModel.sectionTitles.forEach(function (item, idx) {
    +    for (const [idx, item] of Object.entries(loopModel.sectionTitles)) {
           if (item.message) {
             txt.text = item.message;
             txt.x = loopModel.startx + (loopModel.stopx - loopModel.startx) / 2;
    @@ -652,7 +651,7 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
     
             if (hasKatex(txt.text)) {
               loopModel.starty = loopModel.sections[idx].y;
    -          drawKatex(g, txt, loopModel);
    +          await drawKatex(g, txt, loopModel);
             } else {
               drawText(g, txt);
             }
    @@ -663,7 +662,7 @@ export const drawLoop = function (elem, loopModel, labelText, conf) {
             );
             loopModel.sections[idx].height += sectionHeight - (boxMargin + boxTextMargin);
           }
    -    });
    +    }
       }
     
       loopModel.height = Math.round(loopModel.stopy - loopModel.starty);
    @@ -951,9 +950,10 @@ const _drawTextCandidateFunc = (function () {
        * @param textAttrs
        * @param conf
        */
    -  function byKatex(content, g, x, y, width, height, textAttrs, conf) {
    +  async function byKatex(content, g, x, y, width, height, textAttrs, conf) {
         // TODO duplicate render calls, optimize
    -    const dim = calculateMathMLDimensions(content, configApi.getConfig());
    +
    +    const dim = await calculateMathMLDimensions(content, configApi.getConfig());
         const s = g.append('switch');
         const f = s
           .append('foreignObject')
    @@ -968,7 +968,7 @@ const _drawTextCandidateFunc = (function () {
           .append('div')
           .style('text-align', 'center')
           .style('vertical-align', 'middle')
    -      .html(renderKatex(content, configApi.getConfig()));
    +      .html(await renderKatex(content, configApi.getConfig()));
     
         byTspan(content, s, x, y, width, height, textAttrs, conf);
         _setTextAttrs(text, textAttrs);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.