mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +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>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- **fix(sse):** escape backslash before brackets in ChatGPT-web citation link text, preventing a citation label containing `\` from corrupting the generated Markdown link ([#6944](https://github.com/diegosouzapw/OmniRoute/pull/6944)) — thanks @brick30llc-ctrl
|
||||
@@ -49,7 +49,15 @@ function asArray(value: unknown): unknown[] {
|
||||
}
|
||||
|
||||
function markdownLinkText(value: string): string {
|
||||
return value.replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/\n/g, " ").trim();
|
||||
// Escape the backslash first — otherwise a label ending in (or containing) a
|
||||
// backslash leaks past the `[…]` escaping and breaks the generated link, e.g.
|
||||
// `[Path C:\](url)` where the trailing `\` escapes the closing bracket.
|
||||
return value
|
||||
.replace(/\\/g, "\\\\")
|
||||
.replace(/\[/g, "\\[")
|
||||
.replace(/\]/g, "\\]")
|
||||
.replace(/\n/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function markdownUrl(value: string): string {
|
||||
|
||||
50
tests/unit/chatgpt-web-citations-escape.test.ts
Normal file
50
tests/unit/chatgpt-web-citations-escape.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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)");
|
||||
});
|
||||
Reference in New Issue
Block a user