fix(sanitizer): strip alt text from reference-style markdown images (#1488)

stripMarkdownImageAltText removed alt text from inline images
(![alt](url)) but not reference-style images (![alt][ref]), because the
regex requires the "](" of the inline form. Alt text is a
hidden-instruction channel that reaches the prompt via sanitizeContent,
so the reference-style form let it survive.

Add a matching replace for the reference-style form (![alt][ref] ->
![][ref]), preserving the [ref] label so the image definition still
resolves. Adds regression tests.

Co-authored-by: Contributor <you@example.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Humphrey 2026-07-15 22:21:12 -05:00 committed by GitHub
parent e64308ff97
commit 5f509a1c1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 1 deletions

View File

@ -10,7 +10,13 @@ export function stripInvisibleCharacters(content: string): string {
} }
export function stripMarkdownImageAltText(content: string): string { export function stripMarkdownImageAltText(content: string): string {
return content.replace(/!\[[^\]]*\]\(/g, "![]("); // Inline images: ![alt](url) -> ![](url)
content = content.replace(/!\[[^\]]*\]\(/g, "![](");
// Reference-style images: ![alt][ref] -> ![][ref] (keep the label, drop the
// alt text, which is otherwise a hidden-instruction channel just like the
// inline form above).
content = content.replace(/!\[[^\]]*\](\[[^\]]*\])/g, "![]$1");
return content;
} }
export function stripMarkdownLinkTitles(content: string): string { export function stripMarkdownLinkTitles(content: string): string {

View File

@ -59,6 +59,22 @@ describe("stripMarkdownImageAltText", () => {
it("should handle empty alt text", () => { it("should handle empty alt text", () => {
expect(stripMarkdownImageAltText("![](image.png)")).toBe("![](image.png)"); expect(stripMarkdownImageAltText("![](image.png)")).toBe("![](image.png)");
}); });
it("should remove alt text from reference-style images", () => {
expect(stripMarkdownImageAltText("![example alt text][img1]")).toBe(
"![][img1]",
);
expect(
stripMarkdownImageAltText("Text ![description][ref] more text"),
).toBe("Text ![][ref] more text");
});
it("should preserve the reference label of a reference-style image", () => {
// the [ref] label must survive so the image definition still resolves;
// only the alt text (the injection channel) is removed
expect(stripMarkdownImageAltText("![alt][my-ref]")).toBe("![][my-ref]");
expect(stripMarkdownImageAltText("![][keep]")).toBe("![][keep]");
});
}); });
describe("stripMarkdownLinkTitles", () => { describe("stripMarkdownLinkTitles", () => {