From 71151971254f4f8c9308bd55e50fd7239babce8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:05:03 +0000 Subject: [PATCH 1/3] Initial plan From 0560cd1170531ed052fa2966f1650cdc45b4e87d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 12:13:31 +0000 Subject: [PATCH 2/3] fix: add neutralizeMarkdownLinkTitles to allowedAliases branch to close XPIA channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The allowedAliases branch in sanitize_content.cjs was missing a call to neutralizeMarkdownLinkTitles, leaving markdown link titles (invisible hover-text) unstripped — an XPIA steganographic injection channel. - Import neutralizeMarkdownLinkTitles from sanitize_content_core.cjs - Call applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles) after removeXmlComments and before neutralizeMentions in the allowedAliases pipeline (matching sanitizeContentCore ordering) - Add three regression tests covering inline titles, reference-style titles, and @mention titles with allowedAliases specified Agent-Logs-Url: https://github.com/github/gh-aw/sessions/583c7f4c-10fe-4aad-ab16-746044faffce Co-authored-by: szabta89 <1330202+szabta89@users.noreply.github.com> --- actions/setup/js/sanitize_content.cjs | 5 +++++ actions/setup/js/sanitize_content.test.cjs | 25 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/actions/setup/js/sanitize_content.cjs b/actions/setup/js/sanitize_content.cjs index 8218acdcdff..6e659401478 100644 --- a/actions/setup/js/sanitize_content.cjs +++ b/actions/setup/js/sanitize_content.cjs @@ -18,6 +18,7 @@ const { neutralizeCommands, neutralizeGitHubReferences, removeXmlComments, + neutralizeMarkdownLinkTitles, convertXmlTags, applyToNonCodeRegions, neutralizeBotTriggers, @@ -94,6 +95,10 @@ function sanitizeContent(content, maxLengthOrOptions) { // preventing the full pattern from being matched. sanitized = applyToNonCodeRegions(sanitized, removeXmlComments); + // Remove markdown link titles — a steganographic injection channel analogous to HTML comments. + // Must run before mention neutralization for the same ordering reason as removeXmlComments. + sanitized = applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles); + // Neutralize @mentions with selective filtering (custom logic for allowed aliases) sanitized = neutralizeMentions(sanitized, allowedAliasesLowercase); diff --git a/actions/setup/js/sanitize_content.test.cjs b/actions/setup/js/sanitize_content.test.cjs index 15ae3b886ec..5cb2b15f3c5 100644 --- a/actions/setup/js/sanitize_content.test.cjs +++ b/actions/setup/js/sanitize_content.test.cjs @@ -378,6 +378,31 @@ describe("sanitize_content.cjs", () => { const result = sanitizeContent('[text](https://github.com "@exploituser inject payload")'); expect(result).toBe("[text (`@exploituser` inject payload)](https://github.com)"); }); + + it("should neutralize markdown link titles when allowedAliases is specified (XPIA regression)", () => { + // Regression: neutralizeMarkdownLinkTitles must run in the allowedAliases branch too. + // Previously the title was passed through unchanged when allowedAliases were provided. + // The title is moved into the visible link text (no longer steganographic), not stripped. + const result = sanitizeContent('[Result](https://github.com "XPIA: inject")', { allowedAliases: ["author"] }); + expect(result).toBe("[Result (XPIA: inject)](https://github.com)"); + }); + + it("should strip reference-style link titles when allowedAliases is specified", () => { + const result = sanitizeContent('[x][ref]\n\n[ref]: https://github.com "hidden payload"', { + allowedAliases: ["author"], + }); + expect(result).not.toContain("hidden payload"); + expect(result).toBe("[x][ref]\n\n[ref]: https://github.com"); + }); + + it("should neutralize link title @mentions via allowedAliases path without exposing the title steganographically", () => { + // The title @mention must be moved into visible link text and then selectively filtered. + // The allowed alias should remain un-neutralized after being moved to visible text. + const result = sanitizeContent('[text](https://github.com "@author inject")', { + allowedAliases: ["author"], + }); + expect(result).toBe("[text (@author inject)](https://github.com)"); + }); }); describe("XML/HTML tag conversion", () => { From 1e0f7bd4504086b960b31a13a34ca2d10408122b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:19:14 +0000 Subject: [PATCH 3/3] fix: improve comment wording for neutralizeMarkdownLinkTitles in allowedAliases pipeline Agent-Logs-Url: https://github.com/github/gh-aw/sessions/f15821db-6c5f-413b-9d2d-469be2140fd7 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/sanitize_content.cjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/actions/setup/js/sanitize_content.cjs b/actions/setup/js/sanitize_content.cjs index 6e659401478..2ac111037f6 100644 --- a/actions/setup/js/sanitize_content.cjs +++ b/actions/setup/js/sanitize_content.cjs @@ -95,8 +95,10 @@ function sanitizeContent(content, maxLengthOrOptions) { // preventing the full pattern from being matched. sanitized = applyToNonCodeRegions(sanitized, removeXmlComments); - // Remove markdown link titles — a steganographic injection channel analogous to HTML comments. - // Must run before mention neutralization for the same ordering reason as removeXmlComments. + // Neutralize markdown link titles as a hidden/steganographic injection channel analogous to + // HTML comments: inline-link titles are made visible in link text, while reference-style + // titles are stripped. Must run before mention neutralization for the same ordering reason + // as removeXmlComments. sanitized = applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles); // Neutralize @mentions with selective filtering (custom logic for allowed aliases)