diff --git a/.changeset/sanitize-image-element-url.md b/.changeset/sanitize-image-element-url.md
new file mode 100644
index 0000000000000..c2a3a18af8027
--- /dev/null
+++ b/.changeset/sanitize-image-element-url.md
@@ -0,0 +1,6 @@
+---
+'@rocket.chat/gazzodown': patch
+'@rocket.chat/meteor': patch
+---
+
+Sanitizes image URLs in rendered messages to block `javascript:`, `data:`, and `vbscript:` schemes — matching the protection already applied to markdown links. Defense-in-depth against XSS via crafted markdown like ``.
diff --git a/packages/gazzodown/src/Markup.spec.tsx b/packages/gazzodown/src/Markup.spec.tsx
index d4f970d031895..c377e94ec2ed0 100644
--- a/packages/gazzodown/src/Markup.spec.tsx
+++ b/packages/gazzodown/src/Markup.spec.tsx
@@ -345,3 +345,56 @@ it('renders plain text instead of ASCII emojis based on useEmojis preference', (
expect(screen.getByText('Hey! :smile: :)')).toBeInTheDocument();
});
+
+describe('ImageElement sanitization', () => {
+ it.each([['javascript:alert(1)'], ['JAVASCRIPT:alert(1)'], ['data:text/html,'], ['vbscript:msgbox(1)']])(
+ 'replaces dangerous %s scheme with "#" in image href and src',
+ (dangerousSrc) => {
+ render(
+ ,
+ );
+
+ expect(screen.getByRole('link')).toHaveAttribute('href', '#');
+ expect(screen.getByRole('img')).toHaveAttribute('src', '#');
+ },
+ );
+
+ it('preserves safe http(s) image URLs untouched', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByRole('link')).toHaveAttribute('href', 'https://rocket.chat/logo.svg');
+ expect(screen.getByRole('img')).toHaveAttribute('src', 'https://rocket.chat/logo.svg');
+ });
+});
diff --git a/packages/gazzodown/src/elements/ImageElement.tsx b/packages/gazzodown/src/elements/ImageElement.tsx
index e4c6bb08f772d..33d9b401e8fbd 100644
--- a/packages/gazzodown/src/elements/ImageElement.tsx
+++ b/packages/gazzodown/src/elements/ImageElement.tsx
@@ -2,6 +2,8 @@ import type * as MessageParser from '@rocket.chat/message-parser';
import type { ReactElement } from 'react';
import { useMemo } from 'react';
+import { sanitizeUrl } from './sanitizeUrl';
+
const flattenMarkup = (
markup:
| MessageParser.Timestamp
@@ -47,10 +49,11 @@ type ImageElementProps = {
const ImageElement = ({ src, alt }: ImageElementProps): ReactElement => {
const plainAlt = useMemo(() => flattenMarkup(alt), [alt]);
+ const safeSrc = sanitizeUrl(src);
return (
-
-
+
+
);
};