Skip to content

fix(web): show math labels in Mermaid diagrams - #16198

Open
NikitaMGrimm wants to merge 1 commit into
pingdotgg:mainfrom
NikitaMGrimm:fix/mermaid-math
Open

NikitaMGrimm wants to merge 1 commit into
pingdotgg:mainfrom
NikitaMGrimm:fix/mermaid-math

Conversation

@NikitaMGrimm

@NikitaMGrimm NikitaMGrimm commented Oct 5, 2026 •

Copy link
Copy Markdown

Problem

Math in Mermaid diagram labels, such as Note over F: $$f(x)=x^2+3x$$ in a sequence diagram, renders as an empty box. Mermaid draws these labels as KaTeX MathML inside <foreignObject>, and our final DOMPurify pass has no MathML allowlist. DOMPurify then drops <math> and its children, text included.

Change

The final sanitizer now accepts only the MathML that KaTeX emits, instead of DOMPurify's whole MathML profile:

  • Elements: KaTeX's MathML node types (math, mrow, mi, mfrac, msup, mtable, and so on). semantics is still unwrapped with its content kept. annotation, annotation-xml, maction, and mglyph stay removed. Mermaid already strips annotation, and mglyph is KaTeX's trusted-input image.
  • Attributes: KaTeX's presentation attributes (mathvariant, stretchy, fence, columnalign, ...), accepted only on those MathML elements. href, xlink:href, src, and srcset stay forbidden everywhere, and script and event handlers are still removed.
  • DOMPurify's namespace checks still apply. <math> is only accepted under the HTML label inside <foreignObject>, and each child must be in the MathML namespace.

The expanded diagram is a standalone SVG image, so it now also carries the page text color the way it already carries the background. Otherwise, math in dark mode would render black on dark notes. That image is parsed as XML. KaTeX writes spaces in math (\text{total cost}, \quad) as no-break spaces, which HTML serialization outputs as &nbsp;, an entity XML does not define. So the sanitized SVG now uses &#160; instead, which keeps the expanded image from breaking on those labels.

Mermaid's configuration is unchanged, including htmlLabels: false. With that setting, flowchart labels still show $$...$$ as plain text, so this PR does not change flowcharts.

Scope and approval

This is a focused fix for an obvious bug: Mermaid already produces these labels, and our sanitizer erases them. It touches only the shared Mermaid renderer used by web and desktop (chat messages, plans, file and PR markdown previews). Mobile does not render Mermaid. No prior maintainer approval is claimed.

Verification

  • vp test run apps/web/src/components/chat/MermaidDiagram.test.tsx: 4 passed. Against main's sanitizer, the two retention tests fail and the guardrail test passes. The spaced-label test fails without the &#160; replacement. The tests run the real sanitizer on markup captured from Mermaid 11.17.2 and check that:
    • the MathML structure and KaTeX attributes are kept;
    • a label with a no-break space still parses as an SVG image;
    • href, onclick, src, maction, mglyph, annotation-xml, semantics, and annotation are removed;
    • <math> placed directly in SVG is removed;
    • KaTeX attributes on non-MathML elements are stripped.
  • tsc --noEmit for apps/web, plus targeted lint and format checks: clean.
  • Rendered the real MermaidDiagram component in an isolated Vite harness in the T3 Browser, light and dark. Main shows empty notes and an empty message label. With this change, the formulas render inline and in the expanded image. In Chrome, real Mermaid output for $$\text{total cost} = a\quad b$$ parses as an SVG image after sanitizing.

Native Electron and mobile were not run. The browser check used a standalone harness, not the full T3 app.

Before and after: math labels in a Mermaid sequence diagram, dark theme, inline and expanded

Note

🤖 Agent assistance: Opus 5.5 (claude-opus-5-5) via Claude Code

@github-actions github-actions Bot added the size:XS 0-9 changed lines (additions + deletions). label Oct 5, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR is a focused Mermaid rendering fix with targeted tests, but it broadens DOMPurify's handling of markup derived from untrusted diagram content. That sanitizer-policy change has security implications and warrants human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ffb0e012-de3a-4bd9-a652-ebb11887dfba

📥 Commits

Reviewing files that changed from the base of the PR and between d1cf6bc and f1cc8f7.


📒 Files selected for processing (2)
  • apps/web/src/components/chat/MermaidDiagram.test.tsx
  • apps/web/src/components/chat/MermaidDiagram.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.



📝 Walkthrough

Walkthrough

The Mermaid SVG sanitizer now allows selected KaTeX MathML elements and attributes, while retaining restrictions on unsafe content. It converts serialized non-breaking spaces for SVG parsing. Exported diagram images also copy the page’s computed text color.

Changes

Mermaid rendering

Layer / File(s) Summary
MathML sanitization
apps/web/src/components/chat/MermaidDiagram.tsx, apps/web/src/components/chat/MermaidDiagram.test.tsx
sanitizeMermaidSvg allows selected KaTeX MathML elements and presentation attributes, while retaining restrictions on unsafe content. It converts serialized &nbsp; entities to numeric references. Tests check MathML preservation, SVG parsing, and removal of unsafe attributes and disallowed content.
Generated SVG text color
apps/web/src/components/chat/MermaidDiagram.tsx
mermaidImageUrl copies the page’s computed text color as well as its background color.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix


Merge Risk

Merge Risk: ⚪ Minimal · up to f1cc8

No actionable merge-blocking issue is established; merge after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to f1cc8

The change is narrowly scoped and preserves strict diagram rendering and existing script, link, and image restrictions. No introduced attack path was established, but validation of the newly accepted MathML in real browsers and desktop previews remains incomplete.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The relevant attack surface is the client rendering context of someone viewing an attacker-authored diagram: inline page DOM and the generated preview image. A sanitizer bypass could affect that viewer's page context, but this review did not establish such a bypass or increased service authority.

Security Findings and Attack Paths

  • inferred — No introduced executable, navigable, or remote-fetch path was established. The bounded allowlists and retained prohibitions are strong counterevidence. The new tests assert removal of malicious hrefs, event handlers, and remote-image-bearing MathML, but their fixtures do not establish complete browser coverage.

Trust Boundaries and Controls

  • observed — Defense in depth remains: Mermaid uses strict security, disables HTML labels, and protects security-sensitive configuration from diagram directives. The final sanitizer retains forbidden URL attributes and dangerous tags, plus its existing CSS URL filtering. Tests assert MathML namespace preservation in HTML labels and rejection of MathML directly under SVG.

Resilience and Maintainability Implications

  • observed — The shared rendering transition remains serialized around Mermaid's mutable configuration. Sanitization completes before a rendered result is published; failures return structured errors, temporary rendering DOM is removed in finally, and retryable failures can be evicted for retry. Expanded-image replacement retains the existing prior-blob revocation behavior.

Hardening Proposals

  • proposed — Add real-Mermaid browser and desktop fixtures that verify namespace handling and forbidden script, event, and URL behavior through both inline HTML insertion and the expanded XML/blob-image round trip. This would strengthen assurance of the changed boundary, not remediate an established vulnerability.



Pre-merge checks | Passed 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly and concisely describes the main change: displaying math labels in Mermaid diagrams. It uses a conventional commit format and is specific to the affected area.
Description check Passed The description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the sanitizer changes, scope rationale, test results, manual UI checks, limitations, …


✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR


  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@NikitaMGrimm NikitaMGrimm changed the title fix(web): keep math labels in mermaid diagrams fix(web): preserve math labels in Mermaid diagrams Oct 7, 2026
@NikitaMGrimm NikitaMGrimm changed the title fix(web): preserve math labels in Mermaid diagrams fix(web): show math labels in Mermaid diagrams Oct 9, 2026
@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:XS 0-9 changed lines (additions + deletions). labels Oct 9, 2026
@maria-rcks

Copy link
Copy Markdown
Collaborator

Note

Written by claude-opus-5-5 on behalf of Maria

Hi! We are cleaning up open PRs, and this one does not say which model or harness was used to create it. If this change is really important, we recommend rebuilding the PR with a newer model and noting the model and harness in the PR description.

@maria-rcks maria-rcks closed this Oct 11, 2026
@maria-rcks

Copy link
Copy Markdown
Collaborator

Note

Written by claude-opus-5-5 on behalf of Maria

Reopening, this was closed by mistake. Sorry for the noise!

@maria-rcks maria-rcks reopened this Oct 11, 2026

This branch has not been deployed

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants