only render same-origin images in chat replies (#24716)

Assistant markdown rendered any image URL, so a prompt injection in a GenAI description, transcription, or sub label could make the model emit an image pointing at an outside host and the browser would fetch it with chat context in the query string, without a click. Off-origin images now render as their alt text, and off-origin links open in a new tab with noopener noreferrer.
This commit is contained in:
Josh Hawkins
2026-10-19 04:47:05 -10:00
committed by GitHub
parent 6ba3198232
commit 7af29a5a53
2 changed files with 73 additions and 0 deletions
+29
View File
@@ -18,6 +18,18 @@ import { cn } from "@/lib/utils";
import { ChatAttachmentChip } from "@/components/chat/ChatAttachmentChip";
import { parseAttachedEvent } from "@/utils/chatUtil";
import type { ChatStats, ShowStatsMode } from "@/types/chat";
import { baseUrl } from "@/api/baseUrl";
// Assistant output can carry prompt-injected URLs, and the browser fetches
// images without a click, so only same-origin images render.
function isSameOrigin(url: string | undefined): boolean {
if (!url) return false;
try {
return new URL(url, baseUrl).origin === window.location.origin;
} catch {
return false;
}
}
type MessageBubbleProps = {
role: "user" | "assistant";
@@ -223,6 +235,23 @@ export function MessageBubble({
{...props}
/>
),
img: ({ node: _n, src, alt, ...props }) =>
typeof src === "string" && isSameOrigin(src) ? (
<img src={src} alt={alt} {...props} />
) : (
<>{alt}</>
),
a: ({ node: _n, href, ...props }) =>
isSameOrigin(href) ? (
<a href={href} {...props} />
) : (
<a
href={href}
target="_blank"
rel="noopener noreferrer"
{...props}
/>
),
}}
>
{content}