diff --git a/src/link-understanding/detect.test.ts b/src/link-understanding/detect.test.ts index 3b1737e507e0..20e540deee76 100644 --- a/src/link-understanding/detect.test.ts +++ b/src/link-understanding/detect.test.ts @@ -20,6 +20,15 @@ describe("extractLinksFromMessage", () => { expect(links).toEqual(["https://bare.example"]); }); + it("ignores markdown links whose label contains brackets", () => { + // The closing "]" inside the label must not break markdown stripping, otherwise + // the citation URL leaks out as a bare link (with a stray trailing ")"). + const links = extractLinksFromMessage( + "Check [my notes [v2]](https://internal.example/doc) for details", + ); + expect(links).toStrictEqual([]); + }); + it("blocks 127.0.0.1", () => { const links = extractLinksFromMessage("http://127.0.0.1/test https://ok.test"); expect(links).toEqual(["https://ok.test"]); diff --git a/src/link-understanding/detect.ts b/src/link-understanding/detect.ts index 480fd7c3992a..6118dd5aa646 100644 --- a/src/link-understanding/detect.ts +++ b/src/link-understanding/detect.ts @@ -3,7 +3,10 @@ import { isBlockedHostnameOrIp } from "../infra/net/ssrf.js"; import { DEFAULT_MAX_LINKS } from "./defaults.js"; // Remove markdown link syntax so only bare URLs are considered. -const MARKDOWN_LINK_RE = /\[[^\]]*]\((https?:\/\/\S+?)\)/gi; +// The link-text portion allows "]" that is not the closing "](" boundary so +// markdown links whose label contains brackets (e.g. "[my notes [v2]](...)") +// are still stripped instead of leaking their URL to BARE_LINK_RE. +const MARKDOWN_LINK_RE = /\[(?:[^\]]|](?!\())*]\((https?:\/\/\S+?)\)/gi; const BARE_LINK_RE = /https?:\/\/\S+/gi; function stripMarkdownLinks(message: string): string {