mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 17:12:27 +03:00
* fix(sse): escape backslash in ChatGPT-web citation link text (#6569) markdownLinkText() escaped [ and ] but not the backslash itself, so a citation label ending in (or containing) a backslash produced a broken Markdown link — e.g. [Path C:\](url), where the trailing \ escapes the closing bracket and consumes the link. Escape the backslash first, then the brackets. Clears the CodeQL js/incomplete-sanitization alerts at open-sse/executors/chatgpt-web/citations.ts:52 (2 of the 9 new alerts on the v3.8.47 release PR). Regression guard: tests/unit/chatgpt-web-citations-escape.test.ts (trailing backslash, backslash-before-bracket, bracket-only, plain). * chore(changelog): add changelog.d fragment for #6944 Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: brick30llc-ctrl <admin@brick30.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
51 lines
2.2 KiB
TypeScript
51 lines
2.2 KiB
TypeScript
// ChatGPT-web citation link-text escaping (CodeQL js/incomplete-sanitization,
|
|
// PR #6569 release-blocker).
|
|
//
|
|
// `markdownLinkText()` builds the `[text]` half of a Markdown link from an
|
|
// untrusted citation label. It escaped `[` and `]` but NOT the backslash
|
|
// itself, so a label ending in (or containing) a backslash produced a broken
|
|
// link: e.g. `[Path C:\](url)` — the trailing `\` escapes the closing `]`,
|
|
// consuming the link's bracket. The escape character must be escaped first.
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { cleanChatGptText } = await import(
|
|
"../../open-sse/executors/chatgpt-web/citations.ts"
|
|
);
|
|
|
|
const S = ""; // marker start
|
|
const SEP = ""; // marker separator
|
|
const E = ""; // marker end
|
|
|
|
// Build a raw `url` citation marker: url <label> <url>
|
|
const urlMarker = (label: string, url: string) => `${S}url${SEP}${label}${SEP}${url}${E}`;
|
|
|
|
test("markdownLinkText escapes a trailing backslash in the citation label", () => {
|
|
// Label ends in a backslash — without escaping, `[Path C:\](url)` breaks the link.
|
|
const text = `See ${urlMarker("Path C:\\", "https://example.com/docs")} here`;
|
|
const out = cleanChatGptText(text);
|
|
assert.equal(out, "See [Path C:\\\\](https://example.com/docs) here");
|
|
// The backslash must be doubled (escaped), never left bare before the `]`.
|
|
assert.doesNotMatch(out, /[^\\]\\\]/);
|
|
});
|
|
|
|
test("markdownLinkText escapes a backslash preceding a bracket (no bracket leak)", () => {
|
|
const text = urlMarker("a\\[b", "https://example.com");
|
|
const out = cleanChatGptText(text);
|
|
// `\` → `\\`, then `[` → `\[` : label renders as literal `a\[b`.
|
|
assert.equal(out, "[a\\\\\\[b](https://example.com)");
|
|
});
|
|
|
|
test("bracket-only labels keep their existing escaping (regression guard)", () => {
|
|
const text = urlMarker("a[b]c", "https://example.com");
|
|
const out = cleanChatGptText(text);
|
|
assert.equal(out, "[a\\[b\\]c](https://example.com)");
|
|
});
|
|
|
|
test("plain labels with no metacharacters pass through unchanged", () => {
|
|
const text = urlMarker("Plain Title", "https://example.com");
|
|
const out = cleanChatGptText(text);
|
|
assert.equal(out, "[Plain Title](https://example.com)");
|
|
});
|