diff --git a/packages/gitbook/src/app/(global)/~gitbook/image/route.ts b/packages/gitbook/src/app/(global)/~gitbook/image/route.ts index e3895494b..7d1bfde3b 100644 --- a/packages/gitbook/src/app/(global)/~gitbook/image/route.ts +++ b/packages/gitbook/src/app/(global)/~gitbook/image/route.ts @@ -4,8 +4,8 @@ import { verifyImageSignature, resizeImage, CloudflareImageOptions, - checkIsSizableImageURL, imagesResizingSignVersion, + checkIsSizableImageURL, } from '@/lib/images'; import { parseImageAPIURL } from '@/lib/urls'; @@ -28,8 +28,10 @@ export async function GET(request: NextRequest) { const url = parseImageAPIURL(urlParam); - // Prevent infinite loops - if (url.includes('/~gitbook/image')) { + // Check again if the image can be sized, even though we checked when rendering the Image component + // Otherwise, it's possible to pass just any link to this endpoint and trigger HTML injection on the domain + // Also prevent infinite redirects. + if (!checkIsSizableImageURL(url)) { return new Response('Invalid url parameter', { status: 400 }); } @@ -38,12 +40,6 @@ export async function GET(request: NextRequest) { return Response.redirect(url, 302); } - // Check again if the image can be sized, even though we checked when rendering the Image component - // Otherwise, it's possible to pass just any link to this endpoint and trigger HTML injection on the domain - if (!checkIsSizableImageURL(url)) { - return new Response('Invalid url parameter', { status: 400 }); - } - // Verify the signature const verified = await verifyImageSignature(url, { signature }); if (!verified) { diff --git a/packages/gitbook/src/lib/images.ts b/packages/gitbook/src/lib/images.ts index d53597457..476f982cf 100644 --- a/packages/gitbook/src/lib/images.ts +++ b/packages/gitbook/src/lib/images.ts @@ -55,17 +55,26 @@ export function checkIsHttpURL(input: string | URL): boolean { * Check if an image URL is resizable. * Skip it for non-http(s) URLs (data, etc). * Skip it for SVGs. + * Skip it for GitBook images (to avoid recursion). */ export function checkIsSizableImageURL(input: string): boolean { if (!URL.canParse(input)) { return false; } + if (input.includes('/~gitbook/image')) { + return false; + } + const parsed = new URL(input); if (parsed.pathname.endsWith('.svg')) { return false; } - return checkIsHttpURL(parsed); + if (!checkIsHttpURL(parsed)) { + return false; + } + + return true; } interface ResizeImageOptions {