diff --git a/packages/next/src/shared/lib/get-img-props.ts b/packages/next/src/shared/lib/get-img-props.ts index f0fcad0cde358..cdd0cf03a64d0 100644 --- a/packages/next/src/shared/lib/get-img-props.ts +++ b/packages/next/src/shared/lib/get-img-props.ts @@ -465,6 +465,18 @@ export function getImgProps( `Image with src "${src}" has invalid "height" property. Expected a numeric value in pixels but received "${height}".` ) } + // eslint-disable-next-line no-control-regex + if (/^[\x00-\x20]/.test(src)) { + throw new Error( + `Image with src "${src}" cannot start with a space or control character. Use src.trimStart() to remove it or encodeURIComponent(src) to keep it.` + ) + } + // eslint-disable-next-line no-control-regex + if (/[\x00-\x20]$/.test(src)) { + throw new Error( + `Image with src "${src}" cannot end with a space or control character. Use src.trimEnd() to remove it or encodeURIComponent(src) to keep it.` + ) + } } } if (!VALID_LOADING_VALUES.includes(loading)) { diff --git a/test/integration/next-image-new/app-dir/app/invalid-src-leading-space/page.js b/test/integration/next-image-new/app-dir/app/invalid-src-leading-space/page.js new file mode 100644 index 0000000000000..b7682cbc7a95c --- /dev/null +++ b/test/integration/next-image-new/app-dir/app/invalid-src-leading-space/page.js @@ -0,0 +1,11 @@ +import React from 'react' +import Image from 'next/image' + +export default function Page() { + return ( +
+

Invalid src with leading space

+ +
+ ) +} diff --git a/test/integration/next-image-new/app-dir/app/invalid-src-trailing-space/page.js b/test/integration/next-image-new/app-dir/app/invalid-src-trailing-space/page.js new file mode 100644 index 0000000000000..279729491a65c --- /dev/null +++ b/test/integration/next-image-new/app-dir/app/invalid-src-trailing-space/page.js @@ -0,0 +1,11 @@ +import React from 'react' +import Image from 'next/image' + +export default function Page() { + return ( +
+

Invalid src with trailing space

+ +
+ ) +} diff --git a/test/integration/next-image-new/app-dir/test/index.test.ts b/test/integration/next-image-new/app-dir/test/index.test.ts index ebff18725dc5f..25a82501447c6 100644 --- a/test/integration/next-image-new/app-dir/test/index.test.ts +++ b/test/integration/next-image-new/app-dir/test/index.test.ts @@ -915,6 +915,22 @@ function runTests(mode) { ) }) + it('should show invalid src with leading space', async () => { + const browser = await webdriver(appPort, '/invalid-src-leading-space') + expect(await hasRedbox(browser)).toBe(true) + expect(await getRedboxHeader(browser)).toContain( + 'Image with src " /test.jpg" cannot start with a space or control character.' + ) + }) + + it('should show invalid src with trailing space', async () => { + const browser = await webdriver(appPort, '/invalid-src-trailing-space') + expect(await hasRedbox(browser)).toBe(true) + expect(await getRedboxHeader(browser)).toContain( + 'Image with src "/test.png " cannot end with a space or control character.' + ) + }) + it('should show error when string src and placeholder=blur and blurDataURL is missing', async () => { const browser = await webdriver(appPort, '/invalid-placeholder-blur') diff --git a/test/integration/next-image-new/default/pages/invalid-src-leading-space.js b/test/integration/next-image-new/default/pages/invalid-src-leading-space.js new file mode 100644 index 0000000000000..b7682cbc7a95c --- /dev/null +++ b/test/integration/next-image-new/default/pages/invalid-src-leading-space.js @@ -0,0 +1,11 @@ +import React from 'react' +import Image from 'next/image' + +export default function Page() { + return ( +
+

Invalid src with leading space

+ +
+ ) +} diff --git a/test/integration/next-image-new/default/pages/invalid-src-trailing-space.js b/test/integration/next-image-new/default/pages/invalid-src-trailing-space.js new file mode 100644 index 0000000000000..279729491a65c --- /dev/null +++ b/test/integration/next-image-new/default/pages/invalid-src-trailing-space.js @@ -0,0 +1,11 @@ +import React from 'react' +import Image from 'next/image' + +export default function Page() { + return ( +
+

Invalid src with trailing space

+ +
+ ) +} diff --git a/test/integration/next-image-new/default/test/index.test.ts b/test/integration/next-image-new/default/test/index.test.ts index 539b1a8111bd3..7796fc98a0980 100644 --- a/test/integration/next-image-new/default/test/index.test.ts +++ b/test/integration/next-image-new/default/test/index.test.ts @@ -916,6 +916,22 @@ function runTests(mode) { ) }) + it('should show invalid src with leading space', async () => { + const browser = await webdriver(appPort, '/invalid-src-leading-space') + expect(await hasRedbox(browser)).toBe(true) + expect(await getRedboxHeader(browser)).toContain( + 'Image with src " /test.jpg" cannot start with a space or control character.' + ) + }) + + it('should show invalid src with trailing space', async () => { + const browser = await webdriver(appPort, '/invalid-src-trailing-space') + expect(await hasRedbox(browser)).toBe(true) + expect(await getRedboxHeader(browser)).toContain( + 'Image with src "/test.png " cannot end with a space or control character.' + ) + }) + it('should show error when string src and placeholder=blur and blurDataURL is missing', async () => { const browser = await webdriver(appPort, '/invalid-placeholder-blur')