Skip to content

Commit 4947797

Browse files
authored
fix: reorder removeXmlComments before mention neutralization to prevent HTML comment bypass (#25462)
1 parent e212d9d commit 4947797

3 files changed

Lines changed: 29 additions & 6 deletions

File tree

actions/setup/js/sanitize_content.cjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,15 @@ function sanitizeContent(content, maxLengthOrOptions) {
8888
// Neutralize commands at the start of text
8989
sanitized = neutralizeCommands(sanitized);
9090

91+
// Remove XML comments before mention neutralization to prevent bypass: if removeXmlComments
92+
// ran after neutralizeMentions, a comment like <!-- @user payload --> would first become
93+
// <!-- `@user` payload --> and applyFnOutsideInlineCode would split at the backtick boundary,
94+
// preventing the full <!--...--> pattern from being matched.
95+
sanitized = applyToNonCodeRegions(sanitized, removeXmlComments);
96+
9197
// Neutralize @mentions with selective filtering (custom logic for allowed aliases)
9298
sanitized = neutralizeMentions(sanitized, allowedAliasesLowercase);
9399

94-
// Remove XML comments – skip code blocks and inline code
95-
sanitized = applyToNonCodeRegions(sanitized, removeXmlComments);
96-
97100
// Convert XML tags – skip code blocks and inline code
98101
sanitized = applyToNonCodeRegions(sanitized, convertXmlTags);
99102

actions/setup/js/sanitize_content.test.cjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,23 @@ describe("sanitize_content.cjs", () => {
289289
const result = sanitizeContent("Hello <!-- multi\nline\ncomment --> world");
290290
expect(result).toBe("Hello world");
291291
});
292+
293+
it("should remove XML comments containing @mentions (regression: bypass via backtick wrapping)", () => {
294+
// If removeXmlComments ran after neutralizeMentions, the @mention would be wrapped in
295+
// backticks first, splitting the <!--...--> pattern and causing it to survive sanitization.
296+
const result = sanitizeContent("<!-- @exploituser injected payload -->");
297+
expect(result).toBe("");
298+
});
299+
300+
it("should remove XML comments containing multiple @mentions", () => {
301+
const result = sanitizeContent("<!-- @attacker1 and @attacker2 payload -->");
302+
expect(result).toBe("");
303+
});
304+
305+
it("should remove XML comments with @mentions mixed with surrounding text", () => {
306+
const result = sanitizeContent("before <!-- @exploituser payload --> after");
307+
expect(result).toBe("before after");
308+
});
292309
});
293310

294311
describe("XML/HTML tag conversion", () => {

actions/setup/js/sanitize_content_core.cjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,12 +1035,15 @@ function sanitizeContentCore(content, maxLength, maxBotMentions) {
10351035
// Neutralize commands at the start of text (e.g., /bot-name)
10361036
sanitized = neutralizeCommands(sanitized);
10371037

1038+
// Remove XML comments before mention neutralization to prevent bypass: if removeXmlComments
1039+
// ran after neutralizeAllMentions, a comment like <!-- @user payload --> would first become
1040+
// <!-- `@user` payload --> and applyFnOutsideInlineCode would split at the backtick boundary,
1041+
// preventing the full <!--...--> pattern from being matched.
1042+
sanitized = applyToNonCodeRegions(sanitized, removeXmlComments);
1043+
10381044
// Neutralize ALL @mentions (no filtering in core version)
10391045
sanitized = neutralizeAllMentions(sanitized);
10401046

1041-
// Remove XML comments – skip code blocks and inline code to avoid altering code content
1042-
sanitized = applyToNonCodeRegions(sanitized, removeXmlComments);
1043-
10441047
// Convert XML tags to parentheses format – skip code blocks and inline code so that
10451048
// type parameters (e.g. VBuffer<float32>) and code containing angle brackets are preserved
10461049
sanitized = applyToNonCodeRegions(sanitized, convertXmlTags);

0 commit comments

Comments
 (0)