Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions actions/setup/js/sanitize_content.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const {
neutralizeCommands,
neutralizeGitHubReferences,
removeXmlComments,
neutralizeMarkdownLinkTitles,
convertXmlTags,
applyToNonCodeRegions,
neutralizeBotTriggers,
Expand Down Expand Up @@ -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.

Copilot AI Apr 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "Remove markdown link titles", but neutralizeMarkdownLinkTitles does not always remove them (inline-link titles are moved into the visible link text, while reference-style titles are stripped). Consider updating the wording to match the function’s behavior (and the more detailed comment in sanitize_content_core.cjs).

Suggested change
// 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.

Copilot uses AI. Check for mistakes.
sanitized = applyToNonCodeRegions(sanitized, neutralizeMarkdownLinkTitles);

// Neutralize @mentions with selective filtering (custom logic for allowed aliases)
sanitized = neutralizeMentions(sanitized, allowedAliasesLowercase);

Expand Down
25 changes: 25 additions & 0 deletions actions/setup/js/sanitize_content.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down
Loading