diff --git a/src/components/studio/views/chat-subcomponents.tsx b/src/components/studio/views/chat-subcomponents.tsx index 51f2c260..1c82f9eb 100644 --- a/src/components/studio/views/chat-subcomponents.tsx +++ b/src/components/studio/views/chat-subcomponents.tsx @@ -283,7 +283,7 @@ export const MessageList = ({ ) }, img: ({ src, alt }) => { - const safeSrc = typeof src === 'string' && src ? sanitizeUrl(src) : '' + const safeSrc = typeof src === 'string' && src ? sanitizeUrl(src, ['http:', 'https:']) : '' if (!safeSrc) return null return {alt }, diff --git a/src/components/studio/views/editor-preview.tsx b/src/components/studio/views/editor-preview.tsx index 9246d104..b19f188a 100644 --- a/src/components/studio/views/editor-preview.tsx +++ b/src/components/studio/views/editor-preview.tsx @@ -45,6 +45,11 @@ export const EditorPreview = ({ content }: { content: string }) => ( ) }, + img: ({ src, alt }) => { + const safeSrc = typeof src === 'string' && src ? sanitizeUrl(src, ['http:', 'https:']) : '' + if (!safeSrc) return null + return {alt + }, }} > {content || '_Nothing to preview._'} diff --git a/src/lib/security.test.ts b/src/lib/security.test.ts index 713fccd0..d700000d 100644 --- a/src/lib/security.test.ts +++ b/src/lib/security.test.ts @@ -84,6 +84,14 @@ describe('sanitizeUrl', () => { expect(sanitizeUrl('https://example.com', ['ftp'])).toBe('') }) + it('restricts image source protocols when explicit http/https allowlist is passed', () => { + const imageProtocols = ['http:', 'https:'] + expect(sanitizeUrl('https://example.com/image.png', imageProtocols)).toBe('https://example.com/image.png') + expect(sanitizeUrl('http://example.com/image.png', imageProtocols)).toBe('http://example.com/image.png') + expect(sanitizeUrl('mailto:user@example.com', imageProtocols)).toBe('') + expect(sanitizeUrl('tel:+1234567890', imageProtocols)).toBe('') + }) + it('strips ASCII control characters and neutralizes obfuscated scheme payloads', () => { expect(sanitizeUrl('/dashboard\x00path')).toBe('/dashboardpath') expect(sanitizeUrl('/docs\x09setup')).toBe('/docssetup')