11import type { NextApiRequest , NextApiResponse } from "next" ;
22
3- function isValidExternalUrl ( url : string ) : boolean {
3+ // Allow-list of trusted domains for image proxying
4+ const ALLOWED_DOMAINS = [
5+ 'fluidtokens.com' ,
6+ 'aquarium-qa.fluidtokens.com' ,
7+ 'minswap-multisig-dev.fluidtokens.com' ,
8+ // Add more trusted domains as needed
9+ ] ;
10+
11+ function isAllowedDomain ( url : string ) : boolean {
412 try {
513 const parsed = new URL ( url ) ;
614
@@ -9,30 +17,11 @@ function isValidExternalUrl(url: string): boolean {
917 return false ;
1018 }
1119
12- // Block private/internal IP ranges
13- const hostname = parsed . hostname ;
14-
15- // Block localhost and loopback
16- if ( hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' ) {
17- return false ;
18- }
19-
20- // Block private IP ranges (RFC 1918)
21- const privateRanges = [
22- / ^ 1 0 \. / , // 10.0.0.0/8
23- / ^ 1 7 2 \. ( 1 [ 6 - 9 ] | 2 [ 0 - 9 ] | 3 [ 0 - 1 ] ) \. / , // 172.16.0.0/12
24- / ^ 1 9 2 \. 1 6 8 \. / , // 192.168.0.0/16
25- / ^ 1 6 9 \. 2 5 4 \. / , // Link-local
26- / ^ : : 1 $ / , // IPv6 loopback
27- / ^ f c 0 0 : / , // IPv6 private
28- / ^ f e 8 0 : / , // IPv6 link-local
29- ] ;
30-
31- if ( privateRanges . some ( range => range . test ( hostname ) ) ) {
32- return false ;
33- }
34-
35- return true ;
20+ // Check if hostname is in allow-list
21+ const hostname = parsed . hostname . toLowerCase ( ) ;
22+ return ALLOWED_DOMAINS . some ( domain =>
23+ hostname === domain || hostname . endsWith ( '.' + domain )
24+ ) ;
3625 } catch {
3726 return false ;
3827 }
@@ -44,8 +33,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
4433 return res . status ( 400 ) . json ( { error : "Missing src parameter" } ) ;
4534 }
4635
47- if ( ! isValidExternalUrl ( src ) ) {
48- return res . status ( 400 ) . json ( { error : "Invalid or unsafe URL " } ) ;
36+ if ( ! isAllowedDomain ( src ) ) {
37+ return res . status ( 400 ) . json ( { error : "Domain not allowed " } ) ;
4938 }
5039 try {
5140 const controller = new AbortController ( ) ;
0 commit comments