diff --git a/ui/src/ui/markdown.test.ts b/ui/src/ui/markdown.test.ts index 050dd52a166..a600eb49bd6 100644 --- a/ui/src/ui/markdown.test.ts +++ b/ui/src/ui/markdown.test.ts @@ -569,6 +569,20 @@ PY const html = toSanitizedMarkdownHtml("[click](file:///etc/passwd)"); expect(html).toBe("
\n"); }); + + it("strips href from host-local absolute file paths", () => { + const html = toSanitizedMarkdownHtml( + "[report.docx](/Users/test/.openclaw/data/skills/output/report.docx)", + ); + expect(html).toBe("\n"); + }); + + it("keeps app-relative links navigable", () => { + const html = toSanitizedMarkdownHtml("[usage](/usage)"); + expect(html).toBe( + '\n', + ); + }); }); describe("ReDoS protection", () => { diff --git a/ui/src/ui/markdown.ts b/ui/src/ui/markdown.ts index 7ec0461d28f..3f0d64ac197 100644 --- a/ui/src/ui/markdown.ts +++ b/ui/src/ui/markdown.ts @@ -84,6 +84,8 @@ const MARKDOWN_PARSE_LIMIT = 40_000; const MARKDOWN_CACHE_LIMIT = 200; const MARKDOWN_CACHE_MAX_CHARS = 50_000; const INLINE_DATA_IMAGE_RE = /^data:image\/[a-z0-9.+-]+;base64,/i; +const HOST_LOCAL_FILE_HREF_RE = + /^(?:~\/|\/(?:Users|home|tmp|private\/tmp|var\/folders|private\/var\/folders)\/|\/[A-Za-z]:\/|[A-Za-z]:[\\/])/; const markdownCache = new Map