Found by the adversarial fixture run during review of #28. Pre-existing on main, not
a regression from that PR — filing separately so it doesn't creep into its scope.
sanitize in internal/render/mermaid/mermaid.go neutralizes backticks, quotes, square
brackets and newlines, but passes <, > and %% through untouched.
1. A role can restyle the entire diagram
Mermaid directives use %%{...}%%. A role containing one is emitted verbatim into the
generated diagram source and interpreted as a directive rather than as label text:
relationships:
- entity: Policy
cardinality: "1:n"
role: "%%{init:{'theme':'dark'}}%%"
The rendered diagram comes out restyled. A directive is not limited to theming, so the
blast radius is whatever the consuming Mermaid build honours in a directive block.
This matters because *.modelith.yaml files are checked into repositories and rendered
into Markdown that gets committed and published — the input is not always written by the
person reading the output.
2. Angle brackets silently vanish
renders as an empty-looking label — Mermaid's label handling treats it as markup. A model
author using <...> as a placeholder convention loses the text with no diagnostic.
Repro
Fixture and full evidence matrix from the #28 review round:
.scratch/reviews/pr28-fixtures/f16-html-inject.modelith.yaml
.scratch/reviews/pr28-adversarial.md
modelith render f16-html-inject.modelith.yaml
npx -y @mermaid-js/mermaid-cli@11 -i out.mmd -o out.png -b white
Confirmed identical on main and on the #28 branch.
Suggested fix
Extend sanitize to neutralize %% and to escape or replace < / >. Worth auditing at
the same time whether any other Mermaid metacharacter reaches a label unescaped, and
whether the Markdown renderer has the same class of gap — sanitize only guards the
Mermaid path.
Add fixtures for these to the renderer tests so the guarantee is pinned rather than
assumed.
Found by the adversarial fixture run during review of #28. Pre-existing on
main, nota regression from that PR — filing separately so it doesn't creep into its scope.
sanitizeininternal/render/mermaid/mermaid.goneutralizes backticks, quotes, squarebrackets and newlines, but passes
<,>and%%through untouched.1. A
rolecan restyle the entire diagramMermaid directives use
%%{...}%%. A role containing one is emitted verbatim into thegenerated diagram source and interpreted as a directive rather than as label text:
The rendered diagram comes out restyled. A directive is not limited to theming, so the
blast radius is whatever the consuming Mermaid build honours in a directive block.
This matters because
*.modelith.yamlfiles are checked into repositories and renderedinto Markdown that gets committed and published — the input is not always written by the
person reading the output.
2. Angle brackets silently vanish
renders as an empty-looking label — Mermaid's label handling treats it as markup. A model
author using
<...>as a placeholder convention loses the text with no diagnostic.Repro
Fixture and full evidence matrix from the #28 review round:
.scratch/reviews/pr28-fixtures/f16-html-inject.modelith.yaml.scratch/reviews/pr28-adversarial.mdConfirmed identical on
mainand on the #28 branch.Suggested fix
Extend
sanitizeto neutralize%%and to escape or replace</>. Worth auditing atthe same time whether any other Mermaid metacharacter reaches a label unescaped, and
whether the Markdown renderer has the same class of gap —
sanitizeonly guards theMermaid path.
Add fixtures for these to the renderer tests so the guarantee is pinned rather than
assumed.