Found by Copilot review on sync PR #59; the code is upstream's (vendored into markdown-it-myst by jupyter-book#2953, previously in markdown-it-myst-extras). Per our sync-PR policy this is tracked as an issue rather than patched in the merge.
Problem
render_myst_target in packages/markdown-it-myst/src/block.ts interpolates the target label directly into HTML:
const label = token.content;
const target = `<a href="#${label}">(${label})=</a>`;
while TARGET_PATTERN explicitly admits < and > in labels:
const TARGET_PATTERN = /^\((?<label>[a-zA-Z0-9|@<>*./_\-+:]{1,100})\)=\s*$/;
So a target like (<b>x</b>)= injects markup into the rendered output. The file's own escapeHtml helper is used by render_myst_line_comment ten lines above but not here.
Severity
Low: quotes are excluded from the label pattern (no attribute breakout), and this markdown-it HTML render path is used for previews/demos — the main mystmd pipeline goes through tokensToMyst, which is unaffected. Markup injection is possible; full XSS is constrained by the limited character class. Still, the fix is one line (escapeHtml(label) for the text, plus encoding for the fragment), and the helper already exists.
Action
Good first upstream report/PR to jupyter-book/mystmd — not fork-blocking. If we touch markdown-it-myst again for fork work, fix it in passing and add it to the cite-code-span upstream candidate's orbit in UPSTREAM-PRS.yml.
Found by Copilot review on sync PR #59; the code is upstream's (vendored into
markdown-it-mystby jupyter-book#2953, previously inmarkdown-it-myst-extras). Per our sync-PR policy this is tracked as an issue rather than patched in the merge.Problem
render_myst_targetinpackages/markdown-it-myst/src/block.tsinterpolates the target label directly into HTML:while
TARGET_PATTERNexplicitly admits<and>in labels:So a target like
(<b>x</b>)=injects markup into the rendered output. The file's ownescapeHtmlhelper is used byrender_myst_line_commentten lines above but not here.Severity
Low: quotes are excluded from the label pattern (no attribute breakout), and this markdown-it HTML render path is used for previews/demos — the main mystmd pipeline goes through
tokensToMyst, which is unaffected. Markup injection is possible; full XSS is constrained by the limited character class. Still, the fix is one line (escapeHtml(label)for the text, plus encoding for the fragment), and the helper already exists.Action
Good first upstream report/PR to jupyter-book/mystmd — not fork-blocking. If we touch
markdown-it-mystagain for fork work, fix it in passing and add it to the cite-code-span upstream candidate's orbit inUPSTREAM-PRS.yml.