Skip to content

Commit 6929b0b

Browse files
authored
Prevent SVG images to be resized and rendered on the /~gitbook/image endpoint (#2362)
1 parent 7c26d49 commit 6929b0b

File tree

2 files changed

+16
-5
lines changed

2 files changed

+16
-5
lines changed

src/app/(global)/~gitbook/image/route.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { NextRequest } from 'next/server';
22

3-
import { verifyImageSignature, resizeImage, CloudflareImageOptions } from '@/lib/images';
3+
import { verifyImageSignature, resizeImage, CloudflareImageOptions, checkIsSizableImageURL } from '@/lib/images';
44
import { parseImageAPIURL } from '@/lib/urls';
55

66
export const runtime = 'edge';
@@ -27,6 +27,12 @@ export async function GET(request: NextRequest) {
2727
return new Response('Invalid url parameter', { status: 400 });
2828
}
2929

30+
// Check again if the image can be sized, even though we checked when rendering the Image component
31+
// Otherwise, it's possible to pass just any link to this endpoint and trigger HTML injection on the domain
32+
if (!checkIsSizableImageURL(url)) {
33+
return new Response('Invalid url parameter', { status: 400 });
34+
}
35+
3036
// Verify the signature
3137
const verified = await verifyImageSignature(url, { signature, version: signatureVersion });
3238
if (!verified) {

src/lib/images.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function isImageResizingEnabled(): boolean {
4141
/**
4242
* Check if a URL is an HTTP URL.
4343
*/
44-
export function checkIsHttpURL(input: string): boolean {
44+
export function checkIsHttpURL(input: string | URL): boolean {
4545
if (!URL.canParse(input)) {
4646
return false;
4747
}
@@ -54,11 +54,16 @@ export function checkIsHttpURL(input: string): boolean {
5454
* Skip it for non-http(s) URLs (data, etc).
5555
* Skip it for SVGs.
5656
*/
57-
function checkIsSizableImageURL(input: string): boolean {
58-
if (input.endsWith('.svg')) {
57+
export function checkIsSizableImageURL(input: string): boolean {
58+
if (!URL.canParse(input)) {
59+
return false;
60+
}
61+
62+
const parsed = new URL(input);
63+
if (parsed.pathname.endsWith('.svg')) {
5964
return false;
6065
}
61-
return checkIsHttpURL(input);
66+
return checkIsHttpURL(parsed);
6267
}
6368

6469
/**

0 commit comments

Comments
 (0)