diff --git a/src/markdown.test.ts b/src/markdown.test.ts index d7a3742..fc4b513 100644 --- a/src/markdown.test.ts +++ b/src/markdown.test.ts @@ -57,6 +57,19 @@ test("safe Markdown mode keeps HTML examples inert inside code fences", async () assert.match(html, /
 {
+  const html = await renderMarkdown(
+    "[*An Economy of AI Agents*](https://example.com/economy) [**blocked label**](javascript:alert(1))",
+    { allowRawHtml: false },
+  );
+
+  assert.equal(
+    html,
+    '

An Economy of AI Agents blocked label

\n', + ); + assert.doesNotMatch(html, /\*An Economy|javascript:/); +}); + test("safe Markdown mode denies executable link and image protocols", async () => { const html = await renderMarkdown( "[run](javascript:alert(1)) [encoded](javascript:alert(1)) ![payload](data:image/svg+xml,evil) [slash](\\\\evil.example/path) [encoded-slash](\\evil.example/path) ![slash-image](\\\\evil.example/payload.svg) [source](https://example.com/) [local](/knowledge/example)", diff --git a/src/markdown.ts b/src/markdown.ts index 1a271bd..eadf882 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -78,9 +78,9 @@ export async function renderMarkdown( return allowRawHtml ? text : escapeHtml(text); }, ...(!allowRawHtml ? { - link({ href, title, text }) { + link({ href, title, tokens }) { const safeHref = safeMarkdownUrl(href, true); - const label = escapeHtml(text); + const label = this.parser.parseInline(tokens); if (!safeHref) return label; const titleAttribute = title ? ` title="${escapeHtml(title)}"` : ""; return `${label}`;